Keywords for newLISP in the Clojure style

For the Compleat Fan
Locked
rickyboy
Posts: 607
Joined: Fri Apr 08, 2005 7:13 pm
Location: Front Royal, Virginia

Keywords for newLISP in the Clojure style

Post by rickyboy »

Lutz, I was wondering if anyone has asked you about adding a keyword data type to newLISP -- keywords in the style of Clojure, that is. For instance, consider the following. (Sorry that this is an older version of Clojure; however, keywords work the same even in the current version.)

Code: Select all

$ clj
Clojure 1.2.0-master-SNAPSHOT
user=> ;;
user=> ;; Keywords in Clojure are symbols that start with a colon.
user=> ;; They are self-evaluating.
user=> ;;
user=> :x
:x
user=> (= :x :x)
true
user=> (= ':x :x)
true
Like the comment in the REPL session says, keywords are special symbols that evaluate to themselves.

Here are some useful properties of keywords for newLISP use.

1. When you need to use a symbol per se, i.e. you need to use a symbol as a handy tag or token and you are not going to reference it for a value, these keywords are very handy. And since they will never reference another value, you avoid some potential variable capture issues.

2. These kind of keywords don't clutter the context symbol table. They are simply data encountered by eval, which in turn just makes them self-evaluating, like literal numbers, e.g. 42. An ancillary advantage then is that you don't have to quote them.

3. Also, the reader of your code using keywords will recognize that you are using a special class of symbols only as data (literals). The meaning of what you are trying to do with this class of symbols then is much more apparent to the reader, who might be you going back to read your code after 6 months or more. :)

4. These kind of keywords wouldn't belong to a context (see #2 above) and in fact are great at passing around symbols (per se) around from context to context. For instance, have you ever written module code (in a context that's not MAIN) and passed a list constructed by your module back into the MAIN context? In this case, currently newLISP will contextify the symbols, e.g. 'mytag becomes 'mymodule:mytag, when you only wanted to pass back 'mytag.

5. You can use these keywords for a keyword parameter/argument to a function. (Of course, it would just aid you in rolling your own such interface.)

6. You should be able to use such keywords as keys to hash tables (like current newLISP symbols).

There may be more goodness I've overlooked. Lutz, what do you think of this idea as an addition to newLISP? Thoughts, anyone else? Thanks!
(λx. x x) (λx. x x)

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

Re: Keywords for newLISP in the Clojure style

Post by Lutz »

In CodePatterns there is this example for named variables:
http://www.newlisp.org/downloads/CodePa ... html#toc-4 at the end of the chapter

Code: Select all

(define-macro (foo)
   (local (len width height)
      (bind (args) true)
      (println "len:" len " width:" width " height:" height)
   ))

(foo (width 20) (height 30) (len 10)) ;=> len:10 width:20 height:30
but you want the keywords to be global, so you can put functions with named variables into their own namespaces. In newLISP all variables which are created and start with a dollar sign $, are global. So you could do this:

Code: Select all

(context 'CTX)

(define-macro (foo)
   (local ($len $width $height)
      (bind (args) true)
      (println "len:" $len " width:" $width " height:" $height)
   ))

(context MAIN)
now:

Code: Select all

(CTX:foo ($width 20) ($height 30) ($len 10)) ;=> len:10 width:20 height:30
You could even call another function using the same keywords from inside CTX:foo without a problem as the called local restores old bindings on return.

As this function only uses globals as variable you could also shorter write the same this way:

Code: Select all

(define-macro (foo:foo)
   (local ($len $width $height)
      (bind (args) true)
      (println "len:" $len " width:" $width " height:" $height)
   ))


(foo ($width 20) ($height 30) ($len 10)) ;=> len:10 width:20 height:30
the function still lives in its own namespace, but this way it's quicker to write and somewhat easier to read.

conan
Posts: 52
Joined: Sat Oct 22, 2011 12:14 pm

Re: Keywords for newLISP in the Clojure style

Post by conan »

Title could also be "Keywords for newLISP in the Common Lisp style".

I agree those kind of keywords are useful.

Also, is it possible I've seen some macro-stuff here in the forum to emulate them?

rickyboy
Posts: 607
Joined: Fri Apr 08, 2005 7:13 pm
Location: Front Royal, Virginia

Re: Keywords for newLISP in the Clojure style

Post by rickyboy »

Thanks, Lutz!

That answers the mail for item #5. By the way, Clojure-style keywords are used for more than just keyword parameters/arguments for functions[1], but it's good to see that there is a way to do this in newLISP already.

I wrote the original post because I thought that adding a keyword data type might help with a handful of issues (issues other than implementing keyword parameters to functions) that a newLISP programmer might encounter. I'm not averse to dealing with each point directly. For instance item #4 is most interesting to me, and there may be a way to do what I want in newLISP right now.

Say that I want a module to call xml-parse and return SXML to the caller (who is, say, in MAIN). Check this example.

Code: Select all

$ newlisp -C
newLISP v.10.5.0 32-bit on Win32 IPv4/6 libffi, options: newlisp -h

> (context 'mymodule)
mymodule
mymodule> (define (mymodule:parse xml) (xml-type-tags nil nil nil nil) (xml-parse xml 31))
(lambda (xml) (xml-type-tags nil nil nil nil) (xml-parse xml 31))
mymodule> (context MAIN)
MAIN
> (mymodule:parse "<mytag>42</mytag>")
((mymodule:mytag "42"))
>
I certainly want my module code to be in the mymodule context, but I'd like for the call

Code: Select all

(mymodule:parse "<mytag>42</mytag>")
to always return ((mytag "42")), from (a caller in) any context. Can this be accomplished in newLISP now? Thanks for any help!
________________________
[1] That is, Clojure-style keywords are more general than that. They are simply symbols that evaluate to themselves, that you can simply "just use" (as a literal) and they do not pollute symbol tables. As such, they are a handy construct to build such things in the language like keyword parameters to functions, but not only that -- there are other uses too.
(λx. x x) (λx. x x)

rickyboy
Posts: 607
Joined: Fri Apr 08, 2005 7:13 pm
Location: Front Royal, Virginia

Re: Keywords for newLISP in the Clojure style

Post by rickyboy »

conan wrote:Title could also be "Keywords for newLISP in the Common Lisp style".

I agree those kind of keywords are useful.

Also, is it possible I've seen some macro-stuff here in the forum to emulate them?
Thanks, conan! BTW, I'm not sure if there is any "macro-stuff" that implements or emulates them. I'd love to find out. Again, thanks!
(λx. x x) (λx. x x)

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

Re: Keywords for newLISP in the Clojure style

Post by Lutz »

I think Conan posted at the same time as my last post and did not see my post. I think that macro is, what he had seen earlier.

But to xml-parse: you can control the namespace to receive the symbols:

Code: Select all

(context 'mymodule)
(define (mymodule:parse xml)
    (xml-type-tags nil nil nil nil)
    (xml-parse xml 31 MAIN))  ; <- specify target symbol space
(context MAIN)

(mymodule:parse "<mytag>42</mytag>") ;=> ((mytag "42"))
and you could also do this:

Code: Select all

> (bind (mymodule:parse "<mytag>42</mytag>"))
"42"
> mytag
"42"
> 

rickyboy
Posts: 607
Joined: Fri Apr 08, 2005 7:13 pm
Location: Front Royal, Virginia

Re: Keywords for newLISP in the Clojure style

Post by rickyboy »

Lutz wrote:I think Conan posted at the same time as my last post and did not see my post. I think that macro is, what he had seen earlier.
Not sure, but if conan were talking about keywords (in the general sense), as I have, then no. Sorry, I'm trying to direct your attention to a different kind of keyword. The problem of communicating this idea is made all the more difficult for me because there are at least two different programming language concepts that are referred to by the same word here, namely keyword. Yikes! :)

Let me take another stab at it. Here are two different ideas referred to by the term keyword.

1. A keyword is a special kind of symbol that helps a user call a function with arguments in any order, such as in the following.

Code: Select all

> (myfunc :parm2 4 :parm1 2)
Lutz, you showed us how this can be accomplished with your foo macro example. No problem. (And I didn't know this or think about this before, so thanks.)

Here's the other (very different) definition.

2. A keyword is a special kind of symbol that has the following properties.
a. It is not "interned" in any newLISP context, i.e. it doesn't belong to a context and doesn't pollute a context's symbol table.
b. It is self-evaluating, because it is meant to be used as a literal value only.

That's it as regards definition #2. If it were implemented in newLISP, I think it would be considered a new intrinsic data type.

So, every time I wrote "Clojure-style keyword" in my previous posts in this thread, I meant a definition #2 keyword. Definition #2 keywords can be used to implement definition #1 keywords, so that makes them more general in a sense.
Lutz wrote:But to xml-parse: you can control the namespace to receive the symbols:

Code: Select all

(context 'mymodule)
(define (mymodule:parse xml)
    (xml-type-tags nil nil nil nil)
    (xml-parse xml 31 MAIN))  ; <- specify target symbol space
(context MAIN)

(mymodule:parse "<mytag>42</mytag>") ;=> ((mytag "42"))
OK, cool. But I said before, "... I'd like for the call ... to always return ((mytag "42")), from (a caller in) any context." (underline emphasis just added.)

Do I take it that you can't do this in newLISP now? For instance, this doesn't work as I want it to calling from a context other than MAIN.

Code: Select all

> (context 'delme)
delme
delme> (mymodule:parse "<mytag>42</mytag>")
((MAIN:mytag "42"))
delme> (assoc 'mytag (mymodule:parse "<mytag>42</mytag>"))
nil
Lutz wrote:and you could also do this:

Code: Select all

> (bind (mymodule:parse "<mytag>42</mytag>"))
"42"
> mytag
"42"
> 
And even this bind call doesn't bind the symbols into a non-MAIN context -- continuing in context delme:

Code: Select all

delme> (bind (mymodule:parse "<mytag>42</mytag>"))
"42"
delme> mytag
nil
delme> (context MAIN)
MAIN
> mytag
"42"
> ;; bind put it in MAIN though.
If newLISP had definition #2 keywords as a data type, then it wouldn't try to "decorate" the keywords in lists because they would be treated differently by eval. So, in this hypothetical newLISP where keywords are expressed as :x, you could say the following.

Code: Select all

(context 'mymodule)
(define (mymodule:parse xml)
    (xml-type-tags nil nil nil nil)
    (xml-parse xml 31 (keywords true)))  ; <- somehow indicate to xml-parse
                                         ;    to return symbols as keywords
(context MAIN)
(mymodule:parse "<mytag>42</mytag>") ;=> ((:mytag "42"))

(context 'some-other-context)
(mymodule:parse "<mytag>42</mytag>") ;=> ((:mytag "42"))
And that would be JUST ONE application (or usage) of definition #2 keywords. (Sorry for the awkward language.)

It seems that definition #2 keywords can be very useful for newLISP programming in general. I'd love to hear from other newLISPers about if they think that such a construct would be useful for them in their newLISP programming. Thanks for hearing me out again.
(λx. x x) (λx. x x)

conan
Posts: 52
Joined: Sat Oct 22, 2011 12:14 pm

Re: Keywords for newLISP in the Clojure style

Post by conan »

Indeed I was writing my post around the same time Lutz did, so I didn't see his post. That foo macro looks like what I think I saw.

Anyway, rickyboy, I don't know about keywords in Clojure, but I think it stole them from CL, I think Ruby did the same. Well it doesn't matter. I thought you were referring to CL keywords and this is their definition from http://www.lispworks.com/documentation/ ... /t_kwd.htm:
Type KEYWORD
Description:
The type keyword includes all symbols interned the KEYWORD package.
Interning a symbol in the KEYWORD package has three automatic effects:
1. It causes the symbol to become bound to itself.
2. It causes the symbol to become an external symbol of the KEYWORD package.
3. It causes the symbol to become a constant variable.
I also found this one which doesn't add to much, but puts keyword in context with symbols: http://www.mad-computer-scientist.com/b ... mmon-lisp/

I'm not sure it's necessary to make an addition to the language, Lutz already shown that's possible to make named parameters, which solves point five.

Maybe we can just fiddle a little bit with code and see what comes up ;)

So from CL we got: it's a constant, bound to itself (the same symbol) and lives in a special package (we can think about it as a special context, or maybe just a plain context).

I got this:

Code: Select all

; think of the dot context as the CL special Keyword package
(define (.:. a-symbol (a-value nil))
   (constant (sym (term a-symbol))
      (if (true? a-value)
         (eval a-value)
         ; else
         (sym (term a-symbol)))))

Code: Select all

> (. 'y)
.:y
> .:y
.:y
> (. 'y "babula")
"babula"
> .:y
"babula"
The use I like about this kind of "type" is when you wanna pass an option to a function that the only thing it needs to say is "true", in order to do-some-stuff. When you only need to say "true" but you wanna do it in a literate way, they become handy: it's only existence indicates a true value, so we don't need to store a value.

However they can be used to hold a value in CL and, if we want to emulate that, then by making all keywords live in the same "special" context we would get into trouble soon.

The dot functor solves point one because keywords defined with it evaluates by default to itself. Also point two, because they are in the dot context, so no clutter. Also point three, you wrote literate code that way. Point four was addressed by Lutz. Dot functor address point five, just with an extra character. And, finally, I don't know about point six.

In fact I think I need to work more on that dot functor, since I don't like it for holding values, I prefer values stay local, in context.

rickyboy
Posts: 607
Joined: Fri Apr 08, 2005 7:13 pm
Location: Front Royal, Virginia

Re: Keywords for newLISP in the Clojure style

Post by rickyboy »

Hey conan, that's very cool hackery. However, it's not exactly what I was looking for.

First, keywords should just work right off the bat. You should be able to say :y at the prompt and get :y back (as a value). Your method has a "register step" which always has to be performed first, even though only once.

Even if this were tolerable (i.e we dropped expressional convenience as a requirement), there is an additional problem. When you perform the register step:

Code: Select all

> (. 'y)
.:y
you have already polluted the MAIN context with the symbol y. You can see this, when you do a (symbols) right after you've evaluated (. 'y). (And implementing .:. as a macro will still not help.)

Point four was addressed by Lutz, but not resolved as a problem insofar as the particular detail of having symbols which are not bound in contexts (i.e. uninterned symbols). Unfortunately, I think that this makes the implementation of a true keyword (with all the described properties) beyond the reach of user definition — the implementation has to be primitive.

It's a nice try, and believe me I've tried too. My implementation involved a reader-event handler and it also failed vis a vis the problem of having a symbol returned as a value that does NOT pollute some symbol table which you don't want to pollute, like MAIN's. So, I'm with you, man. :)
(λx. x x) (λx. x x)

conan
Posts: 52
Joined: Sat Oct 22, 2011 12:14 pm

Re: Keywords for newLISP in the Clojure style

Post by conan »

First, so you know we're on the same page: I'm for the inclusion of keywords, like the ones I talked above (which I think are the same you're asking for), in newLisp.

However, I'm not quite comfortable with using colon as keyword designator since it already has another uses in newLisp, and even if it can be implemented safely in the interpreter, still will add a burden to the reading programmer: because he/she'll have to interpret which meaning has the colon when reading code. So I root for the use of dot instead. It's an unused character which can be reached with one single keystroke.

I think if we gonna make a case for the inclusion, then we should first try hard to show it cannot be done or cannot be done in a practical way. And second, we should show some cool practical uses for it (in fantasy code, of course, because the thing doesn't exists).

Now, regarding my function, I agree the register step is not to cool:

Code: Select all

; this is awkward
(some-function (. 'with-mustard))
; this is more straightforward
(some-function .with-mustard)
Regarding MAIN pollution, I think that's because of the double pass newlisp does when reading the source, cause anything you type in a symbol place will be added to MAIN:

Code: Select all

$ newlisp
newLISP v.10.5.0 64-bit on Linux IPv4/6 UTF-8, options: newlisp -h

> z
nil
> (symbols)
(...
... z ...)
>
I fixed that problem with this:

Code: Select all

(define (_in-keywords _symbol (_value nil))
    (constant (sym (term _symbol))
        (if (true? _value)
            (eval _value)
            ; else
            (sym (term _symbol))))
    ; in any case delete symbol created inside MAIN
    (unless (true? (eval _symbol))
        (delete _symbol)))
Note: is the same dot functor from my previous post, but I copy pasted from the module attached in this post, where I changed several names for convenience and "safety" (by convention, not real safety).

The deletion is safe, if you got the symbol explicitly defined, then it will not be deleted nor overwritten.

I would like to see your attempts with the reader event handler if you got them handy.

I'm attaching a module Keywords, should have defined a default default functor, but I'm burned out right now. Check it out.

Finally: Lutz has said several times something like: "Don't try to program in newlisp as if it's language <insert-language>". This is not an attempt to make newlisp be like any other language, is stealing from other language what I believe is a nice feature.

... (edit)... After three attempts I couldn't upload the file, board says: "The extension is not allowed". So I'll add it inline:

Code: Select all

#!/usr/bin/env newlisp
;; Creation Date: Tue, 21 May 2013 23:01:38 -0300
;; @author Fernando Canizo (aka conan) - http://conan.muriandre.com/
;; @module Keywords
;; @description Keywords (almost) a-la Common Lisp
;; @version 2013.05.22
;;
;; This module provides a keyword facility for symbols.
;; Use default functor to create keywords like the ones in Common Lisp, which are
;; symbols evaluating to themselves (unless a value is given) living in the
;; Keywords context.
;; Use dash functor to create keywords living on the context from where the
;; function is called.


;; @notes
;; Couldn't make default functor self modifying, had to use _choose-method instead
;; When the chooser was the default functor, newlisp core dumped

(context 'Keywords)


;; @syntax
;; @param
;; @return
;; @example

(define (_choose-method (_method 0))
	(if (= 0 _method) ; store keywords in this context by default
		(setq Keywords:Keywords (append (lambda) (list (first _in-keywords)) (rest _in-keywords)))
		; else
		(setq Keywords:Keywords (append (lambda) (list (first _in-calling-context)) (rest _in-calling-context)))))


;; @syntax
;; @param
;; @return
;; @example

(define (_in-keywords _symbol (_value nil))
	(constant (sym (term _symbol))
		(if (true? _value)
			(eval _value)
			; else
			(sym (term _symbol))))
	; in any case delete symbol created inside MAIN
	(unless (true? (eval _symbol))
		(delete _symbol)))


;; @syntax
;; @param
;; @return
;; @example

(define (_in-calling-context _symbol (_value nil))
	(context (prefix _symbol))
	(constant (sym _symbol)
		(if (true? _value)
			(eval _value)
			; else
			(sym _symbol))))


(context MAIN)
; set a shortcut
(constant '. Keywords)
On a side note: I did some toy-tests to make the default functor be a self modifying function. They worked. But when I tried to do the same with this one, I got a segmentation fault. I'm puzzled.

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

Re: Keywords for newLISP in the Clojure style

Post by Lutz »

Self modification of functions is only safe if the address of the current executing expression is not changed. E.g. the following is possible:

Code: Select all

> (define (foo x y) (push (+ x y) foo -1))
(lambda (x y) (push (+ x y) foo -1))
> (foo 2 3)
5
> foo
(lambda (x y) (push (+ x y) foo -1) 5)
> (foo 6 7)
13
> foo
(lambda (x y) (push (+ x y) foo -1) 5 13)
> 
but the following is not:

Code: Select all

> (define (foo x y) (set 'foo 123))
(lambda (x y) (set 'foo 123))
> (foo)
Segmentation fault: 11
during reassignment of foo the executing expression is destroyed and replaced with new content for foo.

In the first example the currently executing expression is extended during execution. The extension then is the return value.

In other words: modifying a non-executing part of an executing expression is safe, but replacing the part currently executing will crash.

I am following the discussion between you and Rickyboy with great interest and would love to see some real applications of symbols which have that keyword characteristic.

conan
Posts: 52
Joined: Sat Oct 22, 2011 12:14 pm

Re: Keywords for newLISP in the Clojure style

Post by conan »

Relating the side note: I was wrong when I said I made a self-modifying function, I had just modified a function from another one. Interesting use of pop and push, I'll play a little with it later.

To the topic at hand:

We've said keywords could serve three purposes:

1. as one-time-with-no-previous-registration-required flags

2. as named parameters in functions

3. as hash keys

So, real applications that use keywords?

My previous posted _choose-method function is a good example: you want to
decide something inside a function and you just need a flag, no value required.

One option would be to leave it with a number and document it:

Code: Select all

(define (_choose-method (_method 0)) ...)
But if one wanted to make the code more self-describing, could create a couple
of constants:

Code: Select all

(constant 'SAVE_IN_KEYWORDS_CONTEXT 0)
(constant 'SAVE_IN_CALLING_CONTEXT 1)
(define (_choose-method (_method SAVE_IN_KEYWORDS_CONTEXT)) ...)
Using keywords there no need to define the constants and code gets
self-documented:

Code: Select all

(define (_choose-method (_method .save-in-keywords-context))
	(if (true? .save-in-keywords-context) ...))
As you can see, for this use case, is a matter of practicallity, just a
"syntactic convenience" as you explain in the manual for the let form.

Another example, I have a set of PHP functions like these:

Code: Select all

public function select($query, $index_by = null) {
public function select_all_by_pk() {
public function select_all() {
public function select_all_with_foreign_keys()
public function select_one($id) {
public function select_field($id, $field) {
public function select_by_field($field, $value) {
If I were to program these in newlisp, I would like to have just one select
function, and be able to say:

Code: Select all

(select query .index-by-title)
(select .all-by-primary-key)
(select .all)
(select .all-with-foreign-keys)
(select id)
(select id .field-title)
(select field .by-field)
And another one: when you don't need to mix options, like in the function timer, you could use keywords:

Code: Select all

; so 
syntax: (timer sym-event-handler | func-event-handler num-seconds [int-option])
; could become
syntax: (timer sym-event-handler | func-event-handler num-seconds [.real-time | .user-time | .profiling-time])
For the second use case, as named parameters, Lutz shown this:

Code: Select all

(define-macro (foo:foo)
   (local ($len $width $height)
      (bind (args) true)
      (println "len:" $len " width:" $width " height:" $height)
   ))


(foo ($width 20) ($height 30) ($len 10)) ;=> len:10 width:20 height:30
With keywords it would be like this:

Code: Select all

(define-macro (foo:foo)
	(println "len: " .len " width: " .width " height: " .height))

; and called like this:
(foo .width 20 .height 30 .len 10) ; -> len: 10 width: 20 height: 30
And there will not be any global variable, just a property name on a property
list.

For the third case, as hash keywords, this is what we currently have:

Code: Select all

(new Tree 'Myhash)
(Myhash "var" 123) ; create and set variable/value pair
(Myhash "var") → 123 ; retrieve value
With keywords:

Code: Select all

(new tree 'MyHash)
(MyHash .title "The Razors Edge")
(MyHash .year 1990)
(MyHash .artist "AC/DC")
; still allow any string to be a hash symbol
(MyHash "rating" .10/10) ; and allow a keyword to be a value
; look how self-describing is the .10/10 keyword
I don't think it's much of an improvement, besides saving three keystrokes. I think is just and extension of the two previous uses: as a flag holding a meaning, and as a symbol holding a value.

I think the benefit of this kind of type is that it can hold a value: itself, which is just another way of saying "true", or a specific value like in named parameters. And at the same time be self describing.

In my first example one has to resort to cryptic numbers or set constants if self description is desired.
In the .10/10 example, I'm saying with just one keyword: "I'm giving a value of 10 to this CD. Scale goes up to 10."

Note: Maybe I'm blurring the waters with this one. It was a last-minute thought.
Translation: I haven't thought well the last one.

As for the implementation details, I got several doubts. My only certainty is that our keywords should not live all mixed up in a special context called Keywords, but be part of the context they're defined.

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

Re: Keywords for newLISP in the Clojure style

Post by Lutz »

One of the nice things about newLISP is, that contexts / namespaces cover the entire range of using symbols in newLISP.
  • - symbols for primitives (global, protected)
    - symbols for user defined functions
    - symbols as namespace id handle
    - symbols for default functor
    • passed by reference
      used as a hash function if nil
    - symbols as class id in FOOP
    • the class id is the context where methods are defined
    - symbols a variables
and I don't' want to introduce an additional symbol facility, but using existing facilities. E.g.: we could do the following:

Code: Select all

> (define .foo:.foo .foo)
.foo
> .foo
.foo
> 
This would define the keyword symbol .foo which contains itself and is global, it never needs to be prefixed. It is also protected agains accidental redefinition:

Code: Select all

> (set '.foo 123)

ERR: symbol is protected in function set : .foo
> 
Strictly speaking setting the default functor .foo:.foo to .foo in the second arg of the define function, is not necessary. It just prevents .foo to be used as a hash, which only works if the default functor is nil.

The dot would be just a convention, it would work without.
To use in a hash-dictionary you could do the following:

Code: Select all

(new Tree 'MyHash)
; note, that this is really the same as
(define MyHash:MyHash)

> (MyHash (term .foo) "hello world")
"hello world"
> (MyHash (term .foo))
"hello world"
> 
Allowing other data types than strings for hashes is a performance hit, I don't want to take. Using term, which returns a string, also tells the program reader that we are dealing with a special symbol.

So all this would work in the existing version of newLISP. Note that this would create a namespace .foo only containing the default functor. There is no overhead in newLISP for namespaces. So a keyword defined this way, only occupies the memory space of 2 symbols, nothing more. There is also no limit of context symbols in newLISP and they are bound/compiled during load of the source.

The existing namespace could be used for other stuff like keyword help or other attributes, e.g.:

Code: Select all

(define .foo:help "Used as an example")
.foo:help ;=> "Used as an example"
This way to define keywords would not automatically create named variables, but there is the macro presented earlier:
http://www.newlisp.org/downloads/CodePa ... html#toc-4

and other possibilities to make the naming of variables more explicit and safer against errors. This using again a namespace context:

Code: Select all

(define box:box)

(define (measurements obj)
    (case obj
       (box
            (println "width:" obj:width " height:" obj:height " length:" obj:len))
       (paper
            (println "width:" obj:width " height:" obj:height " color:" obj:color))
    ))

(let (box:width 10 box:height 20 box:len 30)
    (measurements box))

;=> width:10 height:20 length:30
In the above example you also could do:

Code: Select all

(define box:box box)
defined like a keyword

What I want to say is: there are so many other facilities in newLISP to give you what named variables give you, which is a less error prone and self-documenting way to pass parameters to user defined functions.

conan
Posts: 52
Joined: Sat Oct 22, 2011 12:14 pm

Re: Keywords for newLISP in the Clojure style

Post by conan »

The intellectual exercise was meant to make us think if the language would
benefit from adding some syntactic sugar. It was never the argument: "This stuff
cannot be done in newlisp without keywords".

Maybe I'm shortsighted, but I think about contexts as the last frontier which
can protect stuff from accidentally being overwritten. An excessive use of
contexts, in my belief, will eventually pollute namespace.

On the other hand, one of the cool things of any lisp-like language is that you
can build one with just seven primitives. So, in lisp-like philosophy, any
addition should be carefully considered, because any addition is more bloat.

Perhaps this is just a matter of taste.

Locked