newLISP development release v.10.1.11

Started by Lutz, February 09, 2010, 12:11:12 PM

Previous topic - Next topic

Lutz

* new functions and additions to older functions



The 10.2 newLISP release notes and the "Deprecated functions" chapter in the users manual show how to make new code compatible with previous versions of newLISP.



files and CHANGES and release notes: http://www.newlisp.org/downloads/development/">http://www.newlisp.org/downloads/development/

itistoday

#1
Where did my makefile_darwin_universal_utf8_compat go? It's no longer with the source distribution. This is a rather important makefile, as with it I am able to safely bundle newlisp scripts with the newlisp binary.
Get your Objective newLISP groove on.

itistoday

#2
Also, looks like caller isn't working as I'd hoped:


> (context 'foo)
foo
foo> (define (foo:foo) (caller))
(lambda () (caller))
foo> (context MAIN)
MAIN
> (foo)
nil


Apparently I have to call (foo) from within a function for caller to be useful, and not even any function but specifically a *user-defined* function. To me this makes caller almost completely useless; I can't define http://newlispfanclub.alh.net/forum/viewtopic.php?f=16&t=3478">for-query-with-db or any other interesting functions with it. :-(



Can you introduce a function, or modify caller so that it returns the context that the function was called from?
Get your Objective newLISP groove on.

Lutz

#3
The universal darwin makefile will be added back.



Regarding 'caller': It returns the calling function, not the context of the function called. See here for valid examples:



http://www.newlisp.org/downloads/development/newlisp_manual.html#caller">http://www.newlisp.org/downloads/develo ... tml#caller">http://www.newlisp.org/downloads/development/newlisp_manual.html#caller



Your example seems to imply, that you want to know the called function's context. You can have that by just returning '(context)' from the called function (not the caller). The reference for 'caller has an example how to get the context of the caller of a function.

itistoday

#4
Quote from: "Lutz"The universal darwin makefile will be added back.


Thanks!


Quote from: "Lutz"Regarding 'caller': It returns the calling function, not the context of the function called. See here for valid examples:


Sorry, I edited my post because I saw that as well, please see the post again.


QuoteYour example seems to imply, that you want to know the called function's context. You can have that by just returning '(context)' from the called function.


No, you seem to have completely misread what I've said here, and in the other thread. context returns the context that the function is in. I need the context from which the function was called.



Here, again, is the function I'm trying to define, please read it:


(define-smacro (for-query-with-db db query)
(letn (db (eval db) sql (db:prepare-sql (eval query)) keys '())
(dotimes (i (sql:col-count))
;(push (sym (upper-case (sql:col-name i)) (prefix (caller))) keys -1)
(push (sym (upper-case (sql:col-name i)) Dragonfly) keys -1)
)
(push-autorelease-pool) ; in case we have blobs
(while (list? (setf values (sql:next-row)))
(eval (expand (cons 'begin $args) (unify keys values)))
)
(pop-autorelease-pool)
(deallocate sql)
)
)


Oddly enough, something is still wrong there. Because even though I do call for-query-with-db from a user-defined function, and even though (prefix (caller)) returns Dragonfly (the context), it doesn't work.



I don't know why it doesn't work, but I get nothing but nils. I have to manually write Dragonfly in (see the uncommented line above, just below the comment-out one), even though that results in an identical function call with the same exact parameters.



I'll repost here how this function is used:


(for-query-with-db db "SELECT name,age FROM people"
     (println NAME " " AGE)
)
Get your Objective newLISP groove on.

itistoday

#5
Here's more bizarro weirdness:


(define-smacro (for-query-with-db db query)
(letn (db (eval db) sql (db:prepare-sql (eval query)) keys '() ctx (prefix (caller)))
(println ctx " vs " (prefix (caller))) ; <-------- WTF?
(dotimes (i (sql:col-count))
;(push (sym (upper-case (sql:col-name i)) (prefix (caller))) keys -1)
;(push (sym (upper-case (sql:col-name i)) ctx) keys -1)
(push (sym (upper-case (sql:col-name i)) Dragonfly) keys -1)
)
(push-autorelease-pool) ; in case we have blobs
(while (list? (setf values (sql:next-row)))
(eval (expand (cons 'begin $args) (unify keys values)))
)
(pop-autorelease-pool)
(deallocate sql)
)
)


When I run that, the call to println prints: "Route.Static vs Dragonfly"



That doesn't make any sense.



The way for-query-with-db is called is as follows:



A function in a context Route.Static calls a function in the Dragonfly context that reads in a file using read-file, this file contains a mix of HTML and inlined newlisp code. This string is converted into a string containing nothing but executable newLISP code. It his then eval'd using the function eval-string in the Dragonfly context. Somewhere in that evaluated code is a call to for-query-with-db, which itself is a macro that is defined within its own context to protect against variable capture (using the define-smacro we discussed in a thread a while ago).
Get your Objective newLISP groove on.

Lutz

#6
QuoteWhen I run that, the call to println prints: "Route.Static vs Dragonfly"


isn't 'Dragonfly' (as a context) what you want to have returned from the caller of '(for-query-with-db db query)' ? Isn't the function which calls '(for-query-with-db db query)' in the 'Dragonfly' context?



In your edit of the post I am still not seeing the difference and I am not sure you understand how 'caller' works ;-?. Did you read the reference for 'caller' in the link I posted? You need a caller for the function called. So there are two functions involved: the caller and the callee who wants to know about the caller's symbol and context.



Also, please post a complete example, boiled down to an absolutely minimum. I am not going through other's code trying to find out what 'define-smacro' does etc..



What I mean is, a completely minimized example with only the necessary to reproduce the effect you want to show, nothing else.



PS: One other (important *) thing when using '(caller)' it makes a difference if the function is called by symbol or by lambda expression. This is an important distinction when using 'map' or 'apply' with a funtion:


(define (foo) (bar))
(define (bar) (caller))

(foo) => foo

(apply foo) => nil    ; calling lambda
(apply 'foo) => foo    ; note the quote


* perhaps this should go into the manual too.

itistoday

#7
Quote from: "Lutz"isn't 'Dragonfly' (as a context) what you want to have returned from the caller of '(for-query-with-db db query)' ? Isn't the function which calls '(for-query-with-db db query)' in the 'Dragonfly' context?


Yes, it is. Do you not see something weird about caller returning Route.Static, and then Dragonfly in the same function?


QuoteIn your edit of the post I am still not seeing the difference and I am not sure you understand how 'caller' works ;-?. Did you read the reference for 'caller' in the link I posted? You need a caller for the function called. So there are two functions involved: the caller and the callee who wants to know about the caller's symbol and context.


I read it, and in my post above I demonstrated my understanding of how caller works by stating:


Quote from: "itistoday"Apparently I have to call (foo) from within a function for caller  to be useful, and not even any function but specifically a *user-defined* function. To me this makes caller almost completely useless; I can't define for-query-with-db or any other interesting functions with it. :-(


Quote from: "Lutz"Also, please post a complete example, boiled down to an absolutely minimum. I am not going through other's code trying to find out what 'define-smacro' does etc..


Unfortunately I don't have time right now to do that (I have a *lot* of stuff I need to finish right now). I think I've done a pretty good job of explaining exactly what the code does and how it's called, and I've certainly demonstrated that caller is broken.



Further, it is not required that I post any condensed version of code (you could do that yourself, I've shown caller is buggy, and I've explained how I use it), because when I originally explained the desire for a function like caller, I described in detail exactly how it should behave, yet this is not what it does. To reiterate:


Quote from: "itistoday"No, you seem to have completely misread what I've said here, and in the other thread. context returns the context that the function is in. I need the context from which the function was called.


If you can't add that, fine. I'll either have to scrap for-query-with-db (and a bunch of other functions that could benefit from a useful caller function) or rewrite it in some manner.
Get your Objective newLISP groove on.

itistoday

#8
Given that it seems the situation is unlikely to change, I've changed the way the function works to be like so:


(define (fn-query-with-db db query func)
(let (sql (db:prepare-sql query) keys '())
(setf keys (map sql:col-name (sequence 0 (-- (sql:col-count)))))
(push-autorelease-pool) ; in case we have blobs
(while (list? (setf values (sql:next-row)))
(func (transpose (list keys values)))
)
(pop-autorelease-pool)
(deallocate sql)
)
)
(global 'fn-query-with-db)


This is the function that will be in the next release of Dragonfly, and if caller is updated in the future to return the calling context, I'll add for-query-with-db as well.



Here is how fn-query-with-db would be used in a template file (slightly more verbose and possibly less efficient, but still, I think, a convenient function):


<table>
<tr class="header"><td>ID</td><td>Name</td><td>Age</td></tr>
<% (fn-query-with-db db "SELECT rowid,name,age FROM people" (fn (row) %>
<tr>
<td><%=(lookup "rowid" row)%></td>
<td><%=(lookup "name" row)%></td>
<td><%=(lookup "age" row)%></td>
</tr>
<% )) %>
</table>
Get your Objective newLISP groove on.

Lutz

#9
The 'caller' function introduced in development version 10.1.11, will be eliminated and not be present in v10.1.12.

m i c h a e l

#10
Goodbye, caller. We had so little time to get to know you. Call again sometime!



m i c h a e l



P.S. When you first announced this release, I wrote but neglected to post the following comment:


QuoteI'm very curious to discover caller's possible role in FOOP. I know this issue came up for me once while working on something (error reporting, I think).


Now I'm glad I didn't ;-)

itistoday

#11
Wow, I just realized something that makes me feel a little silly, I actually didn't need caller at all to do this. :-p



As long as I'm given at least one parameter to the macro which *is* a symbol (literals like strings won't work) then I can get the calling context. In this case the parameter db serves the purpose, and I can use the new prefix function to get the calling context:


(define-smacro (for-query-with-db db query)
(letn (ctx (prefix db) db (eval db) sql (db:prepare-sql (eval query)) keys '() values)
(dotimes (i (sql:col-count))
(push (sym (upper-case (sql:col-name i)) ctx) keys -1)
)
(push-autorelease-pool) ; in case we have blobs
(while (list? (setf values (sql:next-row)))
(eval (expand (cons 'begin $args) (unify keys values)))
)
(pop-autorelease-pool)
(deallocate sql)
)
)


fn-query-with-db will still be there as well, because it has one advantage over for-query-with-db, and that is that because its "body" is stored in a function (and not in the $args list), it can take an optional list of parameters at the end:


(define (fn-query-with-db db query func params , sql keys values)
(when (setf sql (db:prepare-sql query))
(when (or (not params) (sql:bind-params params))
(setf keys (map sql:col-name (sequence 0 (-- (sql:col-count)))))
(push-autorelease-pool) ; in case we have blobs
(while (list? (setf values (sql:next-row)))
(func (transpose (list keys values))))
(pop-autorelease-pool)
)
(deallocate sql)
)
)
(global 'fn-query-with-db)


So now the next update to Dragonfly is going to have a lot of very useful and convenient functions for querying databases (there are currently 5 such functions in the new db/database_utils.lsp plugin).



If you're using the latest bleeding edge from mercurial, you'll find these functions are already available to you.



For comparison, here's how you'd use these two functions:


<table>
<tr class="header"><td>ID</td><td>Name</td><td>Age</td></tr>
<% (fn-query-with-db db "SELECT rowid,name,age FROM people WHERE age < ?" (fn (row) %>
<tr>
<td><%=(<- "rowid" row)%></td>
<td><%=(<- "name" row)%></td>
<td><%=(<- "age" row)%></td>
</tr>
<% ) (list max-age)) %>
</table>
<table>
<tr class="header"><td>ID</td><td>Name</td><td>Age</td></tr>
<% (for-query-with-db db "SELECT rowid,name,age FROM people" %>
<tr>
<td><%=ROWID%></td>
<td><%=NAME%></td>
<td><%=AGE%></td>
</tr>
<% ) %>
</table>
Get your Objective newLISP groove on.