Set or add a pair to a list by reference

Featuring the Dragonfly web framework
Locked
Tim Johnson
Posts: 253
Joined: Thu Oct 07, 2004 7:21 pm
Location: Palmer Alaska USA

Set or add a pair to a list by reference

Post by Tim Johnson »

Here's the sample code:

Code: Select all

(println "<pre>")
(define (set-pair lst key val)  ;; set a pair if found or add it if not found
	(unless(set-ref (list key '?) lst (list key val) match) 
		(push (list key val) attrs -1)))
(set 'attrs '(("ID" "form0") ("method" "POST") ("name" "form0") ("action" "[[action]]")   ;; sample target list
							("onsubmit" "return checkLoginForm(this);")))
(println "Original List:")
(println attrs)
(set 'attr "action")  ;; existing key
(set 'value "mycgiscript.lsp")  ;; new value
(set 'attrs(set-pair attrs attr value))  ;; call the function
(println "\nList Pair Modified:")
(println attrs)   ;; test the result
(set 'attr "newaction")  ;; non-existing (new) key
(set 'value "make weave not lore")  ;; value for key
(set 'attrs(set-pair attrs attr value))  ;; call it
(println "\nList Pair Added:")           ;; display results
(println attrs)
Now, here are the results:

Code: Select all

Original List:
(("ID" "form0") ("method" "POST") ("name" "form0") ("action" "[[action]]") ("onsubmit" 
  "return checkLoginForm(this);"))

List Pair Modified:
(("ID" "form0") ("method" "POST") ("name" "form0") ("action" "mycgiscript.lsp") (
  "onsubmit" "return checkLoginForm(this);"))

List Pair Added:
(("ID" "form0") ("method" "POST") ("name" "form0") ("action" "mycgiscript.lsp") (
  "onsubmit" "return checkLoginForm(this);") 
 ("newaction" "make weave not lore"))
And it works just like I want it to, but three questions evolve from this exercise:
1)How can I pass the 'lst argument by reference so that the 'set-pair function becomes destructive?
Example:

Code: Select all

(set-pair attrs attr value) ;; => 'attrs is changed with calling 'set
2)I come from a background (most recently) in python and rebol, both which pass variables
by reference.
3)I don't believe that Lutz does anything for no good reason:
Why do most newlisp functions pass arguments by value?
Thanks
tim
Programmer since 1987. Unix environment.

Kazimir Majorinc
Posts: 388
Joined: Thu May 08, 2008 1:24 am
Location: Croatia
Contact:

Re: Set or add a pair to a list by reference

Post by Kazimir Majorinc »

1)How can I pass the 'lst argument by reference so that the 'set-pair function becomes destructive?

If that is what you want, write your functions so they accept references, not arguments by references. You can find few examples here: http://newlispfanclub.alh.net/forum/vie ... =16&t=3475 - but example in this post is even better.

2) I come from a background (most recently) in python and rebol, both which pass variables by reference.

Hm... you skipped the question.

3) I don't believe that Lutz does anything for no good reason: Why do most newlisp functions pass arguments by value?

I think that the main reason for that is - ORO. Each object in memory is referenced by only one symbol. If you have function (define (f x) ... ) and it accepts arguments by reference, and you call it with (f y), then y and x both point on the same value. The trick is: think about Newlisp symbols not as variables, but as (generalized) memory addresses in other languages. Just like in other languages, one object in memory cannot be stored in two memory adresses, on the same way, it cannot be stored in two symbols in Newlisp.

Because of that, Newlisp frequently requires one indirection more than other languages (just like assembler does.) But Newlisp is powerful enough so we do not notice it at the first moment, but only when we need to pass large objects as arguments - and our experience with other languages (including other Lisps) might be misleading. And why ORO? There are two other memory management model - manual and garbage collection. Lutz has find some middle ground that allow programmer to do some things without manual memory allocation and deallocation, which is hard on programmer - and without garbage collection - which has its own contra's.

But - for those who really want passing by reference - they can redefine whole Newlisp to do something like:

(set-indirect 'x <expression>) <==> (begin (set 'x 'x-indirection) (set 'x-indirection <expression>))

and then redefine *all* functions in Newlips to accept not only normal arguments, but also the symbols of the form x-indirect and make that indirection.

This is how it can be done:

Code: Select all

(define (indirection? ix)
  (and (symbol? ix)
       (ends-with (string (eval ix)) "-indirection")))      

(dolist (function-name (filter (lambda(x)(primitive? (eval x))) (symbols)))
  (letex((new-function-name (sym (append (string function-name) "-indirect")))
         (function-name function-name))
      (println "Defining " 'new-function-name " using " 'function-name "... ")
      
      (define (new-function-name)
           (let ((indirected-vars (filter indirection? (args))))
           (eval (append (list 'expand (append '(function-name) (args))) (map quote indirected-vars)))))))
           
(define (set-indirect s1 expr1)
   (let ((s1-indirection-name (sym (append (string s1) "-indirection"))))
        (set s1 s1-indirection-name)
        (set s1-indirection-name expr1)))
       
;-----------

(set-indirect 'L '(1 2 3 4 5))

(define (my-reverse-and-insert-zeroes z)
        (reverse-indirect z)
        (push-indirect 0 z)
        (push-indirect 0 z -1))

(my-reverse-and-insert-zeroes L)
(println-indirect "And finally ... " L) ; And finally ... (0 5 4 3 2 1 0)

(set 'M L)
(my-reverse-and-insert-zeroes M)
(println-indirect "Where is ORO? " L M) ;Where is ORO? (0 0 1 2 3 4 5 0 0)(0 0 1 2 3 4 5 0 0)

(exit)
Don't take this code seriously, it is 15 lines written in some half of the hour. It is only proof of the concept, i.e. how Newlisp can be developed in that direction. You can say that one goes through hoops only to achieve what other languages have out of the box, but that kind of flexibility is the essence of Lisp.[/color]

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

Re: Set or add a pair to a list by reference

Post by Lutz »

If you want to pass by reference, you also can use the new FOOP (since development version 10.1.8) as defined here: http://www.newlisp.org/downloads/develo ... lease.html and stable in current development version 10.1.10.

Tim Johnson
Posts: 253
Joined: Thu Oct 07, 2004 7:21 pm
Location: Palmer Alaska USA

Re: Set or add a pair to a list by reference

Post by Tim Johnson »

Kazimir:
The fix is really quite easy. The code becomes

Code: Select all

(define (set-pair lst key val)
	(unless(set-ref (list key '?) (eval lst) (list key val) match) 
		(push (list key val) (eval lst) -1)))
And the call becomes

Code: Select all

(set-pair 'attrs attr value)  ;; no 'set!
Note the use of (eval lst) in the function body and the quoting of the argument in the call.
But the peripheral discussion is of great value to me. Thank you for the code examples
and especially the explanation.
After having my coffee, I realize that question 2) was really not a question, but suffice it
to say, that coming from python, the associative structure of dictionary is quite handy, but
the b-tree nature of the internals makes ordering impossible with the native dict, although derivative
classes with ordering can (and are) created.

I think it would be great if 'set-pair were a native (written in C) newlisp function, but that is just me.
thanks again
tim (finishing-my-coffee 'mug)
Programmer since 1987. Unix environment.

Tim Johnson
Posts: 253
Joined: Thu Oct 07, 2004 7:21 pm
Location: Palmer Alaska USA

Re: Set or add a pair to a list by reference

Post by Tim Johnson »

Lutz wrote:If you want to pass by reference, you also can use the new FOOP (since development version 10.1.8) as defined here: http://www.newlisp.org/downloads/develo ... lease.html and stable in current development version 10.1.10.
Thank you Lutz. I will lay low for a while and try to to digest all of this.
Programmer since 1987. Unix environment.

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

Re: Set or add a pair to a list by reference

Post by itistoday »

Tim Johnson wrote:
Lutz wrote:If you want to pass by reference, you also can use the new FOOP (since development version 10.1.8) as defined here: http://www.newlisp.org/downloads/develo ... lease.html and stable in current development version 10.1.10.
Thank you Lutz. I will lay low for a while and try to to digest all of this.
Obligatory mention of Objective newLISP. It lets you do real pass-by-reference, whereas the new FOOP does not. FOOP (since 10.1.8) has been improved to let you modify a FOOP object without having to create a copy of it, but when you pass the objects around you're still copying them. Link to ObjNL in sig.
Get your Objective newLISP groove on.

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

Re: Set or add a pair to a list by reference

Post by Lutz »

but when you pass the objects around you're still copying them
If you stay in FOOP when passing on objets that is not true. See this example from qa-foop:

Code: Select all

(new Class 'A)
(new Class 'B)

(setq a (A 0 (B 0)))

(define (B:m str)
    (inc (self 1)) )

(define (A:m str)
    (inc (self 1)))

(define (A:qa1)
    (:m (self) (:m (self 2) " hello"))
    (self))

(define (A:qa2)
    (:m (self 2) (:m (self) " hello"))
    (self))

(if (and
        (= (:qa1 a) '(A 1 (B 1)))
        (= (:qa2 a) '(A 2 (B 2))))
    (println ">>>>> FOOP TESTING SUCESSFUL")
    (println ">>>>> ERROR: IN FOOP TESTING")
)
The object gets passed on as 'self' from the ':qa' method to the ':m' method as a reference not as a copy.

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

Re: Set or add a pair to a list by reference

Post by itistoday »

Lutz wrote:If you stay in FOOP when passing on objets that is not true. See this example from qa-foop:
Ah, I didn't know that, but what I said is still mostly true, in 90% of the cases where objects are passed around in a normal OO language, in FOOP they would be passed by value, not by reference.

Here's a trivial example:

Code: Select all

> (new Class 'A)
A
> (new Class 'B)
B
> (define (A:mod b) (:setStr b "foo"))
(lambda (b) (: setStr b "foo"))
> (define (B:setStr str) (setf (self 1) str))
(lambda (str) (setf (self 1) str))
> (set 'a (A) 'b (B "bar"))
(B "bar")
> (:mod a b)
"foo"
> b
(B "bar")
So, you can't use normal functions to pass FOOP objects by reference, and you can't use FOOP methods to modify objects by reference when they are modifying a different object, not themselves.
Get your Objective newLISP groove on.

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

Re: Set or add a pair to a list by reference

Post by Lutz »

itistoday wrote:So, you can't use normal functions to pass FOOP objects by reference
but that is, what I said already:
lutz wrote:If you stay in FOOP when passing on objects that is not true.
You have to stay in FOOP. Your definition of A:mod is not staying in the FOOP paradigm.

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

Re: Set or add a pair to a list by reference

Post by itistoday »

Lutz wrote:You have to stay in FOOP. Your definition of A:mod is not staying in the FOOP paradigm.
Fine, but all that means is that FOOP is a very narrow subset of OOP. Tim wanted to know how to do reference passing in newLISP and I'm just pointing out that most of the time, FOOP is not a good way of doing it.
Get your Objective newLISP groove on.

Tim Johnson
Posts: 253
Joined: Thu Oct 07, 2004 7:21 pm
Location: Palmer Alaska USA

Re: Set or add a pair to a list by reference

Post by Tim Johnson »

What I would like to comment on is not meant to add to or detract from any of conversations going on in this thread,
but consider my observations to be parallel to the topic:

Oftentimes, it appears to me that the concept of OOP becomes a sort of benchmark with which one system or programming
language is measured against another. My experience has been is that OOP is a paradigm, and one of many. A slightly different
perspective was given to me by one of my nieces, also a programmer, who at one time worked for Carl Sassenrath, the developer
of rebol and before that - the amiga operating system. According to her, Carl was fond of saying:
Data drives it!
I refer also to "The Pragmatic Programmer" by Hunt & Thomas and their chapter on Metaprogramming and Metadata. This is
is further impressed on me when I recall my days working with Microsoft Access and it's Property List Driven interfaces.

Python is very strictly engineered and very OOP in nature, yet, it has occurred to me as programmer who usually working on a Code Base alone,
(I often work on multi-programmer projects but individuals work on their own codebase) that perhaps a data-driven paradigm needs
as much of a look as the OOP approach. Indeed, both rebol and newlisp can introspect and manipulate symbols, can use data and code
interchangeably in a way that python does not do. This is why as I learn newlisp, I shall focus more on the functional and list processing
aspects.

And that is why - although I am very interested in newlisp's progress towards OOP/FOOP - I will begin by looking at the list processing and
the functional aspects. Whether passed by reference or not. :)
Programmer since 1987. Unix environment.

Tim Johnson
Posts: 253
Joined: Thu Oct 07, 2004 7:21 pm
Location: Palmer Alaska USA

Re: Set or add a pair to a list by reference

Post by Tim Johnson »

Example follows. First the data structure that "drives it"

Code: Select all

	set form-data [
		"txDBS"[type "select" txt[llabel "Muni:" lj 1] atr[data [(munis)] choice (muni) size 4]]
		"apn" [type "text" txt[llabel "Enter Apn:" lj 1] atr[value (any[apn ""]) size 20 maxlength 20 req[(if not mu/get 'apns)]]
		"apns"[type "select" txt[llabel "OR - Choose APN:" lj 1] atr[data [(*apns*)] size (apn-size)]]
		"submit" [type "submit" txt[llabel ""] atr[value "Next =>"]]
		"reset" [type "reset" txt[llabel ""] atr[value "Reset"]]
		"task" [type "hidden" txt[] atr[value (cgi/get 'task)]]
		"subtask" [type "hidden" txt[] atr[value "save"]]
		]
To translate to newlisp think thusly: Insert 'eval after a opening paren. Convert opening braces to opening parens, closing braces to closing parens
We see that datastructure can contain code also, in the case of the 'req value for key "apn"
Now the 'mu "context" 'loads the data structure

Code: Select all

mu/load form-data ;; the forward slash is 'something' like the colon in newlisp
Now we render the data structure:

Code: Select all

	print htm[
		form/action/method (path) "POST"[
			table[
				tr[td/align "right"[(mu/pop-label "apn")]
				   td/align "left"[(mu/render "apn")]]	
				tr[td/align "right"[(mu/pop-label "txDBS")]
				   td/align "left"[(mu/render "txDBS")]]	
				(apn-list)
				tr[td/align "right"[(mu/render "submit")]
				   td/align "left"[(mu/render "reset")]]]		
			(mu/render "task")(mu/render "subtask")]]
So far, everything from rebol seems translate well to newlisp.
Data drives it.
Go Saints.
Programmer since 1987. Unix environment.

Locked