Request: Function to give context given symbol

Started by itistoday, February 03, 2010, 03:04:25 PM

Previous topic - Next topic

itistoday

This would be a lifesaver, I've found myself needing this so many times: a function to give me the context of a symbol.



I.e. check out this awesome function:


(define-smacro (for-query-with-db db query ctx)
(letn (db (eval db) sql (db:prepare-sql query) keys '())
(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)
)
)


It can't live because the body ($args) uses symbols in a different context. I have to manually *tell* 'sym' what context the symbols in the body are coming from.



This function is going to be in Dragonfly 0.61, it will let you do stuff like this:


<table>
<tr><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>


That's pretty great, but currently this will just show a bunch of nil's. To get it to show the right values I have to hack it up and make it ugly:


<table>
<tr><td>ID</td><td>Name</td><td>Age</td></tr>
<% (for-query-with-db db "SELECT rowid,name,age FROM people" DF %>
<tr><td><%=ROWID%></td><td><%=NAME%></td><td><%=AGE%></td></tr>
<% ) %>
</table>


I could get rid of that 'DF' on the end if there was a (sym->ctx) function available. There are so many other cool things you could do if such a function existed. Can such a function be brought into newLISP?



Edit: updated function definition to use 'expand' and 'unify'
Get your Objective newLISP groove on.

Lutz

#1
There is one in the next version:


newLISP v.10.1.11 on OSX IPv4 UTF-8, execute 'newlisp -h' for more info.

> (setf s 'Foo:bar)
Foo:bar
> (path s)
Foo
> (context? (path s))
true
> (context (path s))
Foo
Foo>

itistoday

#2
Awesome! Thanks Lutz! :-D



(I would only advise against using 'path' for the name, as that is probably used in a lot of existing newlisp code, and making it a primitive would break all of that code).
Get your Objective newLISP groove on.

itistoday

#3
Also, will it work with non-symbols? i.e:


(define-macro (blah x) (path x))
(blah "asdf") => MAIN
Get your Objective newLISP groove on.

TedWalther

#4
Perhaps "path" would be too easily confused with basename/filename type of operations?  Perhaps "context-of" would be a better name?



Ted
Cavemen in bearskins invaded the ivory towers of Artificial Intelligence.  Nine months later, they left with a baby named newLISP.  The women of the ivory towers wept and wailed.  \"Abomination!\" they cried.

Kazimir Majorinc

#5
I like "context-of". Use of "of", "is", "from", "to" etc. is, I believe, good naming practice.
http://kazimirmajorinc.com/\">WWW site; http://kazimirmajorinc.blogspot.com\">blog.

Lutz

#6
Symbol names as strings:



It cannot work on strings because the context of a symbol is encoded with the symbol. The symbol with the name "blah" could be in several contexts. One could check if "blah" is present in a specific context:


(sym "blah" (context) nil) => nil
(sym "blah" MAIN nil) => nil
(sym "blah" Foo nil) => Foo:blah


This tells us that "blah" is not present in the current context and not in MAIN, but is defined in Foo. The 'nil' parameter tells 'sym' not to create the symbol, if not present.



Naming of the new function:



Name clashes with new function names are always a possibility, and we always have had these in the past. I remember introducing 'name', which caused a lot of clashes being used in many web forms. I don't think it is a good practice to make the name more complicated for the sake of avoiding name clashes. Perhaps it should be practice to making variable names in programs more descriptive.



Conceptually 'name' and 'path' belong together:


(set 's 'Foo:bar)
(= s (sym (name s) (path s))) => true


In other areas in computing, i.e. file systems, the same labels are used to describe tree structures. See: path-name or pathname, path in a symbol tree.



Fortunately built-in symbols are protected. So a name clash is pretty obvious accompanied by an error message.

TedWalther

#7
Thanks for the reminder about the (name) function.  I see your point, and agree; name and path are a good pairing.
Cavemen in bearskins invaded the ivory towers of Artificial Intelligence.  Nine months later, they left with a baby named newLISP.  The women of the ivory towers wept and wailed.  \"Abomination!\" they cried.

itistoday

#8
Quote from: "Lutz"Symbol names as strings:



It cannot work on strings because the context of a symbol is encoded with the symbol. The symbol with the name "blah" could be in several contexts. One could check if "blah" is present in a specific context:


I think you misunderstood me, and I think it's my fault.  I think what I'm asking for is may not be addressed by this path function. In the original function that I gave, what I want to be able to do is to find out the context an fexpr is called in. Here's an updated version of it using path:


(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)) (path query)) 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)
)
)


See the (path query)?  I want that to return the context that the fexpr was called in, because otherwise I can't use 'for-query-with-db' in any context other than its own (without manually specifying it when calling it).
Get your Objective newLISP groove on.

Lutz

#9
You mean the callee knowing about the caller?


(define (Bar:func) (caller)) ; or (path (caller))
(define (Foo:func) (Bar:func))

(Foo:func) => Foo:func  ; or Foo

itistoday

#10
Quote from: "Lutz"You mean the callee knowing about the caller?


(define (Bar:func) (caller)) ; or (path (caller))
(define (Foo:func) (Bar:func))

(Foo:func) => Foo:func  ; or Foo


Yes! (path (caller)) looks like it should work, especially if it works with macros as well. I can only imagine the kinds of things you could do with this. Many thanks!
Get your Objective newLISP groove on.

xytroxon

#11
I always think of the file system when I see path...



And why wouldn't it be called root? As in finding the symbol's root context... Calling it path also seems to imply the path of a nested context...



And Dragonfly uses "path" in it's framework libraries, breaking a site's installation on a minor newLISP release...



If I remember right, Clojure uses find-ns ie find name space...



From the newlisp manual: context

-----------------------------------------------

In the second syntax, context can be used create symbols in a namespace.

-----------------------------------------------

(Also found a manual error: can be used to create symbols ;)


newLISP v.10.1.11 on OSX IPv4 UTF-8, execute 'newlisp -h' for more info.

> (setf s 'Foo:bar)
Foo:bar
> (namespace s)
Foo
> (context? (namespace s))
true
> (context (namespace s))
Foo
Foo>


-- xytroxon
\"Many computers can print only capital letters, so we shall not use lowercase letters.\"

-- Let\'s Talk Lisp (c) 1976

itistoday

#12
I second (third?)  xytroxon's comments, and I think he picked a good names for it; 'namespace' is good, 'root' is slightly less descriptive and more likely to break existing code, but it's still better than 'path'. I think breaking existing code frequently by using commonly used names like 'name' and 'path' is a bad thing, and could scare people away from newlisp. Further, 'path' is a legitimate name to use for many other things, it would be a great loss to not be able to use it.
Get your Objective newLISP groove on.

m i c h a e l

#13
Since contexts are namespaces in newLISP, wouldn't namespace and context be in conflict?



m i c h a e l

itistoday

#14
Quote from: "m i c h a e l"Since contexts are namespaces in newLISP, wouldn't namespace and context be in conflict?


That's a good point, in light of that I vote for Kazimir's context-of.
Get your Objective newLISP groove on.