newLISP development release v.10.1.11

Notices and updates
Locked
Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

newLISP development release v.10.1.11

Post by 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/

itistoday
Posts: 429
Joined: Sun Dec 02, 2007 5:10 pm
Contact:

Re: newLISP development release v.10.1.11

Post by itistoday »

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
Posts: 429
Joined: Sun Dec 02, 2007 5:10 pm
Contact:

Re: newLISP development release v.10.1.11

Post by itistoday »

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

Code: Select all

> (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 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
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Re: newLISP development release v.10.1.11

Post by Lutz »

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/develo ... tml#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
Posts: 429
Joined: Sun Dec 02, 2007 5:10 pm
Contact:

Re: newLISP development release v.10.1.11

Post by itistoday »

Lutz wrote:The universal darwin makefile will be added back.
Thanks!
Lutz wrote: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.
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.
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:

Code: Select all

(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:

Code: Select all

(for-query-with-db db "SELECT name,age FROM people"
     (println NAME " " AGE)
)
Last edited by itistoday on Tue Feb 16, 2010 3:00 am, edited 1 time in total.
Get your Objective newLISP groove on.

itistoday
Posts: 429
Joined: Sun Dec 02, 2007 5:10 pm
Contact:

Re: newLISP development release v.10.1.11

Post by itistoday »

Here's more bizarro weirdness:

Code: Select all

(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).
Last edited by itistoday on Tue Feb 16, 2010 2:59 am, edited 2 times in total.
Get your Objective newLISP groove on.

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Re: newLISP development release v.10.1.11

Post by Lutz »

When 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:

Code: Select all

(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
Posts: 429
Joined: Sun Dec 02, 2007 5:10 pm
Contact:

Re: newLISP development release v.10.1.11

Post by itistoday »

Lutz wrote: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?
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.
I read it, and in my post above I demonstrated my understanding of how caller works by stating:
itistoday wrote: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. :-(
Lutz wrote: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:
itistoday wrote: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
Posts: 429
Joined: Sun Dec 02, 2007 5:10 pm
Contact:

Re: newLISP development release v.10.1.11

Post by itistoday »

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

Code: Select all

(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):

Code: Select all

<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>
Last edited by itistoday on Tue Feb 16, 2010 2:59 am, edited 1 time in total.
Get your Objective newLISP groove on.

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Re: newLISP development release v.10.1.11

Post by Lutz »

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
Posts: 394
Joined: Wed Apr 26, 2006 3:37 am
Location: Oregon, USA
Contact:

Re: newLISP development release v.10.1.11

Post by m i c h a e l »

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:
I'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
Posts: 429
Joined: Sun Dec 02, 2007 5:10 pm
Contact:

Re: newLISP development release v.10.1.11

Post by itistoday »

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:

Code: Select all

(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:

Code: Select all

(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:

Code: Select all

<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.

Locked