Author Topic: Declaring variables in nested functions  (Read 25653 times)

0 Members and 1 Guest are viewing this topic.

Daniel J. Ellis

  • Swamp Rat
  • Posts: 811
Declaring variables in nested functions
« on: February 04, 2009, 08:32:26 AM »
I'm not entirely sure where to declare my variables when they're generated in nested functions  for example:

(DEFUN c:runthis ( / a )
   (SETQ a (MULTIPLIER 2)
  (PRINC "\nA:")(PRINC a)
)

(DEFUN multiplier (b / c )
  (SETQ c (GETINT ("\nEnter number to multiply:")))
  (SETQ a (* b c))
)

So where do I need to declare variable a?  Or can I not, do I need to end RUNTHIS with a (SETQ a nil)?

dJE
===
dJE

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Declaring variables in nested functions
« Reply #1 on: February 04, 2009, 08:39:51 AM »
No need for a in the sub function. Just do this:
Code: [Select]
(DEFUN c:runthis ( / a )
   (SETQ a (MULTIPLIER 2))
  (PRINC "\nA:")(PRINC a)
)
(DEFUN multiplier (b / c )
  (SETQ c (GETINT ("\nEnter number to multiply:")))
  (* b c) ; return value
)
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

Daniel J. Ellis

  • Swamp Rat
  • Posts: 811
Re: Declaring variables in nested functions
« Reply #2 on: February 04, 2009, 01:01:40 PM »
OK thanks.

How about, in a slightly more complicated scenario:

(DEFUN multiplier ( b start step / )
  (IF
    (>= b start)
    (IF
      (<= b start)
      (SETQ a (+ b step))
      (SETQ a b)
    )
    (SETQ ab)
  );IF
)

dJE
===
dJE

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Declaring variables in nested functions
« Reply #3 on: February 04, 2009, 01:30:57 PM »
You can use
Code: [Select]
(DEFUN multiplier ( b start step / tmp)
  (IF (>= b start)
    (IF (<= b start)
      (SETQ tmp (+ b step))
      (SETQ tmp b)
    )
    (SETQ tmp b)
  )
  tmp
)


OR
Code: [Select]
(DEFUN multiplier ( b start step / tmp)
  (IF (>= b start)
    (IF (<= b start)
      (+ b step)
      b
    )
    b
  )
)

As long as you are looking for a return value to setq to a
a doesn't have to be defined within the subroutine.
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

Daniel J. Ellis

  • Swamp Rat
  • Posts: 811
Re: Declaring variables in nested functions
« Reply #4 on: February 04, 2009, 01:43:29 PM »
Fantastic, thankyou so much Alan.

Can the list at the end of the routine (tmp) be of more than one variable?

I'm working on a lisp that reads a string and uses WCMATCH to split it into one of a number of types, counting how many of each type I have in the drawing.  This is based around a COND statement with each condition containing (SETQ gcount (1+ gcount)), (SETQ cpcount (1+ cpcount)), or (SETQ pcount (1+ pcount)), could I just go

(DEFUN blah
    (COND.....
    )
 gcount
 cpcount
 pcount
)

?

dJE
===
dJE

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Declaring variables in nested functions
« Reply #5 on: February 04, 2009, 04:14:11 PM »
You have to put the variables in a list to return more than one & then extract them from the list.
Code: [Select]
(DEFUN c:test (/ gcount cpcount pcount lst)
  (setq lst (VarInc 4 nil 5))
  (if (car lst) (SETQ gcount (car lst)))
  (if (cadr lst) (SETQ cpcount (cadr lst)))
  (if (caddr lst) (SETQ pcount (caddr lst)))
  (princ)
)


(DEFUN VarInc (gcnt cpcnt pccnt)
    (and gcnt (setq gcnt (1+ gcnt)))
    (and cpcnt (setq cpcnt (1+ cpcnt)))
    (and pccnt (setq pccnt (1+ pccnt)))
  (list gcnt cpcnt pccnt)
)
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

JohnK

  • Administrator
  • Seagull
  • Posts: 10625
Re: Declaring variables in nested functions
« Reply #6 on: February 04, 2009, 05:57:26 PM »
I will not get into the variable scope questions this post (im going home now)  but i quickly wanted to say:

`SET' is better.

Code: [Select]
;; this is a reproduction of yours
(and a (setq a (1+ a)))

;; a variation (easier to understand)
(set 'a (1+ a))

;; Example:
;; If you run those lines you will get nothing...
;; lets establish `a' and re-run those lines

(setq a 6)
;; now that we have a symbol (variable, name, etc) filled, lets increment it

(and a (setq a (1+ a)))
; Would return `T'

(set 'a (1+ a))
; Would return `7'


;; Therefore

(DEFUN VarInc (gcnt cpcnt pccnt)
    (and gcnt (setq gcnt (1+ gcnt)))
    (and cpcnt (setq cpcnt (1+ cpcnt)))
    (and pccnt (setq pccnt (1+ pccnt)))
  (list gcnt cpcnt pccnt)
)
;; Becomes...

(defun varinc ( gcnt cpcnt pccnt / )
  (set 'gcnt (1+ gcnt))
  (set 'cpcnt (1+ cpcnt))
  ;; ...
  (list gcnt cpcnt pccnt)

)

;; Or even something like...

(defun varinc ( gcnt cpcnt pccnt /  ++1 )
  (defun ++1 ( v )
     (set v (1+ (eval v))) )

  (++1 'gcnt)
  (++1 'cpcnt)

  ;; ...
)


« Last Edit: February 04, 2009, 06:43:27 PM by Se7en »
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

Daniel J. Ellis

  • Swamp Rat
  • Posts: 811
Re: Declaring variables in nested functions
« Reply #7 on: February 04, 2009, 07:14:08 PM »
OK, so ignoring scope of variables, which is something I've never heard of before ^_^, so suits me fine...

I'm very concerned about your use of a stray "AND a," I assume that should be part of some sort of error trapping system (presumably in an IF statement), which you've not shown here for clarity.  Your note at the end *seems* to imply they shouldn't really be there?  Although the phrase "proper form" would contradict that.  You've thoroughly tied me in knots!

You don't include the "AND a" in the SET statements.

The use of SET seems to require a list, which I would rather avoid since it requires additional processing.

Other than that I can't see any difference between SETQ and SET from your example.  From looking at Hyperpics, it would appear that SETQ can handle multiple expressions (SETQ a 1 b 2 c 3...)  whilst SET cannot.  This is something I tend to do, because I think it produces neater code when printed.

I think my question about multiple SETQs has led us up the garden path slightly, each iteration will work on at most one of gcount, pcount, etc., sometimes on none of them.  I guess this leads me back to my original question:  At what stage should I declare these variables, or am I better doing a (SETQ gcount nil pcount nil ) after their last use?

Sorry if I've competely misunderstood you

dJE

Looking back over the thread, it seems that Alan introduced the whole AND issue, but I missed it.  Is it some kind of replacement for  COND?
===
dJE

Chuck Gabriel

  • Guest
Re: Declaring variables in nested functions
« Reply #8 on: February 04, 2009, 07:40:39 PM »
If the first operand of an AND function evaluates to nil, the rest of the expression won't evaluate.  You can use it to avoid errors caused by trying to perform an operation on a nil value.

JohnK

  • Administrator
  • Seagull
  • Posts: 10625
Re: Declaring variables in nested functions
« Reply #9 on: February 04, 2009, 07:44:19 PM »
I will talk about `lexical scope' in a bit.

However, Don't concern yourself with the and statement; it came out wrong and i removed it so it didnt cause any confusion (but you obviously saw it...sorry 'bout that.). Just concern yourself with the differences between SET and SETQ -i.e. SET will evaluate both arguments where SETQ will only evaluate the second.  Yes you can not stack expressions with SET (It will only handle one expression at a time) but that isnt all bad sometimes.

> The use of SET seems to require a list, which I would rather avoid since it requires additional processing.

SET does not require a list it requires a SYMBOL (If i understand your question).

AND can be a sort of replacement for COND but not really because COND can return a `process' (I cant think of a better word right now) not a symbol. Basically the typical COND you may be used to seeing is/could be technically speaking wrong (or overkill if you will).  
Code: [Select]
(cond
  ((test
    (process
  (T  ;; <-- Thats overkill
   (process
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

JohnK

  • Administrator
  • Seagull
  • Posts: 10625
Re: Declaring variables in nested functions
« Reply #10 on: February 04, 2009, 07:53:59 PM »
yeah, after re-reading this thread; i think i may have inadvertently directed you down a path you were not intending to go down. But, its a cool lesson if you wish to continue?
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Declaring variables in nested functions
« Reply #11 on: February 04, 2009, 09:39:57 PM »
DJE
I though I would introduce you to AND in the subroutine.
Used the way I did it functions like an IF but only returns t or nil.
Because the return value was not a factor in that usage I threw it in there for you to see.
This routine :
Code: [Select]
(DEFUN VarInc (gcnt cpcnt pccnt)
    (and gcnt (setq gcnt (1+ gcnt)))
    (and cpcnt (setq cpcnt (1+ cpcnt)))
    (and pccnt (setq pccnt (1+ pccnt)))
  (list gcnt cpcnt pccnt)
)

could use the IF in place of the ANDs and the return value of the IFs could be captured
in the LIST and thus eliminate this line (list gcnt cpcnt pccnt)
Like this:
Code: [Select]
(DEFUN VarInc (gcnt cpcnt pccnt)
  (list
    (if gcnt (setq gcnt (1+ gcnt)))
    (if cpcnt (setq cpcnt (1+ cpcnt)))
    (if pccnt (setq pccnt (1+ pccnt)))
  )
)
As Chuck pointed out I used the AND to test the variable for a nil value because you can not (1+ nil) :)
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

Daniel J. Ellis

  • Swamp Rat
  • Posts: 811
Re: Declaring variables in nested functions
« Reply #12 on: February 05, 2009, 02:04:51 AM »
So using SET would save me having to do a (SETQ gcount 0) earlier on in my code?

This is something I've done in my "initialisation" code, partly to make sure the variables *are* reading 0 (rather than continuing an old value) and to side step that problem.

I was right about the AND being error trapping then :)

OK, so the difference between SETQ and SET seems to be that SET can "equate" nil and 0, while SETQ can't.  One can't stack expressions with SET but can with SETQ.

dJE

I will talk about `lexical scope' in a bit.

However, Don't concern yourself with the and statement; it came out wrong and i removed it so it didnt cause any confusion (but you obviously saw it...sorry 'bout that.). Just concern yourself with the differences between SET and SETQ -i.e. SET will evaluate both arguments where SETQ will only evaluate the second.  Yes you can not stack expressions with SET (It will only handle one expression at a time) but that isnt all bad sometimes.

> The use of SET seems to require a list, which I would rather avoid since it requires additional processing.

SET does not require a list it requires a SYMBOL (If i understand your question).

AND can be a sort of replacement for COND but not really because COND can return a `process' (I cant think of a better word right now) not a symbol. Basically the typical COND you may be used to seeing is/could be technically speaking wrong (or overkill if you will).  
Code: [Select]
(cond
  ((test
    (process
  (T  ;; <-- Thats overkill
   (process
===
dJE

Daniel J. Ellis

  • Swamp Rat
  • Posts: 811
Re: Declaring variables in nested functions
« Reply #13 on: February 05, 2009, 02:10:28 AM »
OK, the AND if making more sense now.  I suppose in full, the If statements should include setting the count to 1 if it was at nil:

Code: [Select]
(DEFUN VarInc (gcnt cpcnt pccnt)
  (list
    (if gcnt (setq gcnt (1+ gcnt))(setq gcnt 1))
    (if cpcnt (setq cpcnt (1+ cpcnt))(setq cpcnt 1))
    (if pccnt (setq pccnt (1+ pccnt)(setq pccnt))
  )
)

Does the use of AND get round that? (i.e. by using AND do I no longer need to find somewhere to (SETQ gcount 0))

dJE

DJE
I though I would introduce you to AND in the subroutine.
Used the way I did it functions like an IF but only returns t or nil.
Because the return value was not a factor in that usage I threw it in there for you to see.
This routine :
Code: [Select]
(DEFUN VarInc (gcnt cpcnt pccnt)
    (and gcnt (setq gcnt (1+ gcnt)))
    (and cpcnt (setq cpcnt (1+ cpcnt)))
    (and pccnt (setq pccnt (1+ pccnt)))
  (list gcnt cpcnt pccnt)
)

could use the IF in place of the ANDs and the return value of the IFs could be captured
in the LIST and thus eliminate this line (list gcnt cpcnt pccnt)
Like this:
Code: [Select]
(DEFUN VarInc (gcnt cpcnt pccnt)
  (list
    (if gcnt (setq gcnt (1+ gcnt)))
    (if cpcnt (setq cpcnt (1+ cpcnt)))
    (if pccnt (setq pccnt (1+ pccnt)))
  )
)
As Chuck pointed out I used the AND to test the variable for a nil value because you can not (1+ nil) :)

===
dJE

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Declaring variables in nested functions
« Reply #14 on: February 05, 2009, 05:22:47 AM »
Quote
So using SET would save me having to do a (SETQ gcount 0) earlier on in my code?

No, (set 'a (1+ a)) or (setq (quote a) (1+ a)) is the same as (setq a (1+ a)) if a is nil an error will occur.

set function evaluates the following expression setq doesn't. setq is an abbreviation for set (quote ...)
Speaking English as a French Frog

Daniel J. Ellis

  • Swamp Rat
  • Posts: 811
Re: Declaring variables in nested functions
« Reply #15 on: February 05, 2009, 08:37:48 AM »
OK, thanks for your help everybody.  Trying to conclude:

  • If a subroutine produces a single variable, one can eliminate the call to the "produced" variable in the subroutine, simply calling the result of the operation in the subroutine, and declaring the variable in the outter function
  • If a subroutine produces more than one variable they can either be collected into a list, effectively mimicking a single variable, or one needs to SETQ nil those variables after their final use
  • Disregarding "lexical scope," which I'll discuss later, the only practical difference between SET and SETQ is that with SETQ, multiple pairings (SETQ a 1 b 2 c 3 etc) can be made in one statement, with SET they can't

Lexical Scope
From a quick internet search, it would appear that with a lexical scope, a variable can be assigned a value, but this value cannot be changed; if a dynamic scope is used the value of that variable can be changed as the program is run.
Based on Se7en's initial mention of lexical scoping, I take it that SET is lexical, while SETQ is dynamic?  On this basis I assume that (SET a (1+ a)) wouldn't work because a if fixed, whereas (SETQ b (1+ b)) would work because b is dynamic?

dJE
===
dJE

JohnK

  • Administrator
  • Seagull
  • Posts: 10625
Re: Declaring variables in nested functions
« Reply #16 on: February 05, 2009, 09:48:06 AM »
Well my train fell off its tracks.

Scope:

wikipedia?  No matter. Lexical and dynamic scoping is defined on how the interpreter searches for variables not necessarily what you can do to them per se. That is a loaded statement because the SEARCH can dictate the binding we may find, and if and how we can MODIFY that binding...Scope is a very broad subject that can cause your ears to ring.

Generally speaking:
Autolisp can look up a previously defined variable. SET and SETQ can modify the binding of those variables.
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Declaring variables in nested functions
« Reply #17 on: February 05, 2009, 09:59:53 AM »
danellis,

I'am not sure to understand what you mean by "lexical scope" but I think you didn't undertsand the main difference between SET and SETQ.
Quote
I assume that (SET a (1+ a)) wouldn't work because a if fixed

(set a (1+ a)) won't work, but it's not because a is "fixed", it's because SET evaluates a and this evaluation returns a number, not a symbol.
IOW
(set a ...) is the same as (setq (eval a) ...)
(set (quote a) ...) is the same as (setq a ...)

Have look to this little squence on the commande line
Quote
Commande: (setq a 1)
1
Commande: (setq b (quote a)) ; this is the same as (setq b 'a)
A
Commande: !a
1
Commande: !b
A
Commande: (eval b)
1
Commande: (set b 2)
2
Commande: !a
2
Commande: !b
A
Commande: (eval b)
2
« Last Edit: February 05, 2009, 10:47:07 AM by gile »
Speaking English as a French Frog

JohnK

  • Administrator
  • Seagull
  • Posts: 10625
Re: Declaring variables in nested functions
« Reply #18 on: February 05, 2009, 10:08:51 AM »
<snip>
but I think you didn't undertsand the main difference between SET and SETQ.
<snip>

I dont think i understood the initial NEED.  ...I was aiming to eventually touch on the fact that SET can accept an evaluation as its first argument. I was wrong about his intentions and i said that i was mistaken and that i was sorry to lead him down the wrong path.  I will go back to my corner now.
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

Daniel J. Ellis

  • Swamp Rat
  • Posts: 811
Re: Declaring variables in nested functions
« Reply #19 on: February 05, 2009, 12:51:29 PM »
My ears are completely ringing!!  Sorry about your train, I didn't mean to derail it lol

I often find wikipedia a good place to find fairly simple explaination of terms it that way. Obviously it (or more likely I), failed on this occasion.

I think I can put it in the "entirely irrelevant" category and forget all about it.  I'm aware that that was your original intention, I'd only caught on to it trying to find a difference between SET and SETQ.

Well my train fell off its tracks.

Scope:

wikipedia?  No matter. Lexical and dynamic scoping is defined on how the interpreter searches for variables not necessarily what you can do to them per se. That is a loaded statement because the SEARCH can dictate the binding we may find, and if and how we can MODIFY that binding...Scope is a very broad subject that can cause your ears to ring.

Generally speaking:
Autolisp can look up a previously defined variable. SET and SETQ can modify the binding of those variables.
===
dJE

Daniel J. Ellis

  • Swamp Rat
  • Posts: 811
Re: Declaring variables in nested functions
« Reply #20 on: February 05, 2009, 12:58:32 PM »
This thread had become me trying to establish the difference between SET and SETQ!!  "Scope" was a red herring of a word that at one point I thought might explain that difference.

I think I may understand now:
  • using SETQ one may assign a value to a variable, that value can be alphabetical, numerical, or the result of a function or of another variable
  • by way of contrast SET can only assign a variable to another variable
  • EVAL is a way of trying to make SETQ act like SET
  • QUOTE is a way of trying to make SET act like SETQ

dJE
danellis,

I'am not sure to understand what you mean by "lexical scope" but I think you didn't undertsand the main difference between SET and SETQ.
Quote
I assume that (SET a (1+ a)) wouldn't work because a if fixed

(set a (1+ a)) won't work, but it's not because a is "fixed", it's because SET evaluates a and this evaluation returns a number, not a symbol.
IOW
(set a ...) is the same as (setq (eval a) ...)
(set (quote a) ...) is the same as (setq a ...)

Have look to this little squence on the commande line
Quote
Commande: (setq a 1)
1
Commande: (setq b (quote a)) ; this is the same as (setq b 'a)
A
Commande: !a
1
Commande: !b
A
Commande: (eval b)
1
Commande: (set b 2)
2
Commande: !a
2
Commande: !b
A
Commande: (eval b)
2
===
dJE

JohnK

  • Administrator
  • Seagull
  • Posts: 10625
Re: Declaring variables in nested functions
« Reply #21 on: February 05, 2009, 01:29:41 PM »

no the only difference is that SETQ can NOT accept an evaluation as its first argument, SET can.
Code: [Select]
(setq a nil
      b nil
      c nil
      d nil)
; lets do some setup and clear a b c d vars just in case they are set.

(setq d 1)
; now create and one variable called d and fill it with the number 1

; pretending that we had a sitauation where we did not know what variable was used
; but we knew the range; we can run a small invesigation to discover it.

; to return the variable used...
(set
  ;; find the variable already defined (leave the others untouched)
  ;; and fill it with a number 7
  ;;
  ;; the second argument to SET can also be an evaluation
  ;; of a process but we are just going to set a number
  ;; for this example.
  (cond
    (a 'a)
    (b 'b)
    (c 'c)
    (d 'd) )
  7 )

; see the values of the variables to ensure that we didnt touch any other variable besides d
(mapcar 'eval '(a b c d))
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

Daniel J. Ellis

  • Swamp Rat
  • Posts: 811
Re: Declaring variables in nested functions
« Reply #22 on: February 05, 2009, 03:25:51 PM »
OK, let's see if I can understand that:

The setup is a nice and conventional SETQ.  :)

We've got a COND nested in a SET.
The COND looks at a, if a exists, turn it into a list
If a doesn't exist, it looks at b, and if that exists, turns it into a list
If b doesn't exist, the COND looks at c, and if that exists, turns it into a list
finally, if c doesn't exist, it looks at d, and if d exists, turns it into a list

The SET then turns assigns the value 7 to any variable that is a list.

That all seems to make sense, *except* that this seems to revolve around SET only working on lists, which you said earlier it didn't (you implied that SET can work on non-lists as well), unless the SET is filtering for the "nil"s, but then why would you need the COND statement?

It looks like SET can work on variables without knowing beforehand which variable it's working on.  Except that doesn't seem to save on any coding:
(COND
  ((a)(SETQ a 'a))
  ((b)(SETQ b 'b))
  ((c)(SETQ c 'c))
  ((d)(STEQ d 'd))
)

or would it start saving code if a more complicated example?

dJE


no the only difference is that SETQ can NOT accept an evaluation as its first argument, SET can.
Code: [Select]
(setq a nil
      b nil
      c nil
      d nil)
; lets do some setup and clear a b c d vars just in case they are set.

(setq d 1)
; now create and one variable called d and fill it with the number 1

; pretending that we had a sitauation where we did not know what variable was used
; but we knew the range; we can run a small invesigation to discover it.

; to return the variable used...
(set
  ;; find the variable already defined (leave the others untouched)
  ;; and fill it with a number 7
  ;;
  ;; the second argument to SET can also be an evaluation
  ;; of a process but we are just going to set a number
  ;; for this example.
  (cond
    (a 'a)
    (b 'b)
    (c 'c)
    (d 'd) )
  7 )

; see the values of the variables to ensure that we didnt touch any other variable besides d
(mapcar 'eval '(a b c d))

===
dJE

dustinthiesse

  • Guest
Re: Declaring variables in nested functions
« Reply #23 on: February 05, 2009, 03:50:09 PM »
The COND looks at a, if a exists, turn it into a list
If a doesn't exist, it looks at b, and if that exists, turns it into a list
If b doesn't exist, the COND looks at c, and if that exists, turns it into a list
finally, if c doesn't exist, it looks at d, and if d exists, turns it into a list

(a 'a) does not mean it is turning 'a' into a list.

While quote can be used to form lists, in this case the quote just returns the symbol without evaluating it.

Daniel J. Ellis

  • Swamp Rat
  • Posts: 811
Re: Declaring variables in nested functions
« Reply #24 on: February 05, 2009, 04:57:56 PM »
OK.

So a is still nil?
===
dJE

Daniel J. Ellis

  • Swamp Rat
  • Posts: 811
Re: Declaring variables in nested functions
« Reply #25 on: February 05, 2009, 04:59:54 PM »
Are you guys trying to tell me that I could for example

(SET a ( * 10))?

dJE
===
dJE

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Declaring variables in nested functions
« Reply #26 on: February 05, 2009, 05:15:14 PM »
To understand the difference between SET and SETQ, you have to understand the difference between EVAL and QUOTE (').

assigning a quoted expression to a variable
_$ (setq a (quote (+ 1 2)))
(+ 1 2)

the variable stores the unevaluated expression
_$ a
(+ 1 2)

forcing evaluation using eval
_$ (eval a)
3

SET always evaluates its first argument, so it's used with expressions which evaluation returns a symbol.
Here're three examples of set using

Code: [Select]
;;assigning a list of variables using mapcar
(setq pt (getpoint))
(mapcar '(lambda (sym val) (set sym val)) '(x y z) pt)

SET is needed because sym have to be evaluated to return x, then y, then z.
Repalacing SET by SETQ will avoid sym evaluation.
In the same way, to reset x,y and z to nil:

Code: [Select]
(foreach sym '(x y z) (set sym nil))
To create incremental variables SET can be used to evaluate a (read ...) expression which returns a symbol

Code: [Select]
(setq n 1)
(while (setq pt (getpoint))
  (set (read (strcat "pt" (itoa n))) pt)
  (setq n (1+ n))
)
« Last Edit: February 05, 2009, 05:20:16 PM by gile »
Speaking English as a French Frog

Daniel J. Ellis

  • Swamp Rat
  • Posts: 811
Re: Declaring variables in nested functions
« Reply #27 on: February 06, 2009, 08:03:13 AM »
OK, from another read of the thread, and a little trial-and-error on the command line, I think I understand, so here we go:

  • EVAL figures out what an expression actually means, so (EVAL (+ 1 2)) figuers out that 1 + 2 = 3
  • QUOTE just repeats an expression, so (QUOTE (+ 1 2)) would result in a display of "(+ 1 2)"  It leaves the expression completely alone, it just repeats it.
  • SETQ figures out what an expression actually means, and saves it to a variable, so (SETQ a (+ 1 2)) figures out that 1 + 2 = 3 and so saves 3 to a.  SETQ Can take anything, numbers, letters, or other variables as its input
  • SET is trying to be like SETQ, but can't quite manage it: it can only do stuff to other variables, so (SET a (+ 1 2)) produces an error, one first has to define variables for SET, such as (SETQ d 1 e 2) (SET a (+ d e)) would then look up d (1), look up e (2), then add them together (3) and save the result to a


dJE

(edit:  there's really no reason to quote the previous thread.)
===
dJE

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Declaring variables in nested functions
« Reply #28 on: February 06, 2009, 09:10:58 AM »
At the risk of muddying up the waters I'm going to step in here and offer my explanation.
You can scream & holler if I cause you any distress. :)

From the HELP file.
Quote
SET
The set function is similar to setq except that set evaluates both of its arguments whereas setq only evaluates its second argument.

Both set and setq expect a symbol as their first argument, but set accepts an expression that returns a symbol, whereas setq does not, as the following shows:

Code: [Select]
Command: (set (read "a") 5.0)
5.0

Command: (setq (read "a") 5.0)
; *** ERROR: syntax error

My examples of how you may use this feature of set.

Code: [Select]
;;  indirect set variables to nil
(mapcar '(lambda (x)(set (read x) nil)) (list "var1" "var2")) ; note that the variable name is in quotes!

;;  indirect set variables to value
(mapcar '(lambda (x y)(set (read x) y)) '("var1" "var2") '(2 3))

(+ var1 var2)
5

;;=========================================================
;;  get variables stored in list
(defun get_saved_vars ()
  ;;  extract variables from  global variable list
  (mapcar
    'set
    '(tid_filename  mtflag       pickangle     repeattxt
      repeatins     StripCodes   UpperCase     txtang
      useleader     usedimtxt    Keep:Dim      Keep:Txt
      Keep:Lay      Use:OvrRide  txt:lst:ptr   *DiaLoc*
      )
      textinsertdclvars  ; This variable is a list of values, see function below
  )
) ; defun get_saved_vars

;;=========================================================
;;  save variables in a global variable list
(defun put_saved_vars ()
  (setq textinsertdclvars
         (list
           tid_filename   mtflag       pickangle     repeattxt
           repeatins      StripCodes   UpperCase     txtang
           useleader      usedimtxt    Keep:Dim      Keep:Txt
           Keep:Lay       Use:OvrRide  txt:lst:ptr   *DiaLoc*)
  )
) ; defun put_saved_vars

;;=========================================================
If you are not comfortable with mapcar yet here is a foreach example.
Code: [Select]
;;  Change/Set values to zero
(foreach var '("mCount" "fCount" "hCount" "dCount" )
     (set (read x) 0)
)
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Declaring variables in nested functions
« Reply #29 on: February 06, 2009, 09:21:12 AM »
Here is one more example.
This will create variables with a prefix of "ListVar" and in this case it will create 7 different variables.
With this method you may create as many variables as needed.

Code: [Select]
;;  CAB 10.25.2007
(defun c:test (/ lst VarBase ndx)
  (setq lst     '(1 2 3 4 5 6 7)
        VarBase "ListVar"
        ndx     1
  )
  (foreach itm lst
    (set (read (strcat VarBase (rtos ndx 2 0))) itm)
    (setq ndx (1+ ndx))
  )
  (print ListVar3)
  (print ListVar6)
  (princ)
)
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: Declaring variables in nested functions
« Reply #30 on: February 06, 2009, 09:22:42 AM »
<I shouldn't be posting yet as I haven't had my first coffee but this thread has been bugging me, so forgive me if it lacks some coherency>

About quote, setq and set ...

Quote (') simply instructs the lisp interpreter "return an expression without evaluating it" (from the help), so if a statement is quoted, e.g. '(+ 2 2) or (quote (+ 2 2)) ... it is not evaluated, thus does not return 4 but the term '(+ 2 2). If a symbol is quoted it similarly is not evaluated but returned as a symbol, e.g. assuming the symbol b hosts hosts the value 42, 'b,  or (quote b) will not return 42 but the symbol b.

Now has does this manifest itself with set / setq? It's right in the help file: "The set function is similar to setq except that set evaluates both of its arguments whereas setq only evaluates its second argument."

Say what? First setq.

(setq a b) ... assuming b is bound to the value 42 from before a is now bound to 42. Remember "setq only evaluates its second argument". So the symbol a is not evaluated, but b is evaluated, thus the symbol a is bound to the value 42.

Wait a second, isn't (setq a b) the same as (set 'a b)? Yes it is, setq is merely a convenience function.

Now set.

But what if we don't quote the first term when using set? If you don't quote the first term it is evaluated, which can cause problems if you don't understand what the ramifications are, and haven't initialized a accordingly. As exists currently, a is bound to 42, so if we tried to execute this statement (set a 7) we would get an error, because we would be trying to bind the value 7 to ... the value of 42.

What?

Again, given that a is currently bound to 42, (set a 7) once a is evaluated (value 42) would be analogous to (setq 42 7) which is of course, impossible.

So how do you use set?

Well if you want to set the symbol a to something you would use either (setq a something) or (set 'a something).

However, if you want to take advantage of what is sometimes referred to as "indirect addressing", that is, use one symbol to bind another symbol to some value then the following may illuminate. In order for this work the first symbol must point to another symbol, for example (setq a 'b) or (set 'a 'b). Now we can bind the symbol b to some value using the symbol a: (set a 7). The symbol b is now bound to the value 7.

So ... all this seems academic, where would you use this in the real world? To be honest, it doesn't come up that frequently, is frequently misused, but here are a couple uses.

;; bind the symbols x, y and z to the values 1, 2 and 3 respectively.
(mapcar 'set '(x y z) '(1 2 3))

;; null out the values for multiple symbols
(foreach x '(a b c) (set x nil))

I'd post more but I'm late for work as it is and gotta run.

Edit: After typing out all this sht CAB beat me to it; grrrrr, later.

ciao
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: Declaring variables in nested functions
« Reply #31 on: February 06, 2009, 09:26:24 AM »
Here is one more example ...

Be careful using that technique as you are creating / using variables which have global scope. :)
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Declaring variables in nested functions
« Reply #32 on: February 06, 2009, 09:27:39 AM »
Even without coffee you quite clear headed.   :roll:
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Declaring variables in nested functions
« Reply #33 on: February 06, 2009, 09:34:02 AM »
Here is one more example ...

Be careful using that technique as you are creating / using variables which have global scope. :)

You would need this when your were through with the variables.
Code: [Select]
(mapcar '(lambda (x)(set (read x) nil)) varlst)
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: Declaring variables in nested functions
« Reply #34 on: February 06, 2009, 09:39:25 AM »
You would need this when your were through with the variables ...

And if another program happened to be using those (global) variables? While creating vars on the fly is interesting academically, the same can usually be replicated using judicious list management using local scope, which imo is safer and more readily understood, especially if you write code for others. Just sayin'. :)
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Declaring variables in nested functions
« Reply #35 on: February 06, 2009, 09:59:41 AM »
And well said.  8-)
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Declaring variables in nested functions
« Reply #36 on: February 06, 2009, 10:04:34 AM »
Very nice explaination MP, really more readable than what I tried to write in my poor English :|
Speaking English as a French Frog

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: Declaring variables in nested functions
« Reply #37 on: February 06, 2009, 10:40:54 AM »
Thanks guys. Wish Tony would have piped in, he could have said it better in half the verbiage. If he doesn't beat me to it I'll rewrite what I penned below, but I've too many guns pointed at my head write now.
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Declaring variables in nested functions
« Reply #38 on: February 06, 2009, 04:32:15 PM »
<I shouldn't be posting yet as I haven't had my first coffee but this thread has been bugging me, so forgive me if it lacks some coherency>

About quote, setq and set ...

< .... >
ciao

Morning Michael ... It's been bugging me too, and I was planning on commennting today { Saturday morning ( but I HAVE coffee)}
looks like you've covered the relevant points and better than I'd be able to.
:)
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Daniel J. Ellis

  • Swamp Rat
  • Posts: 811
Re: Declaring variables in nested functions
« Reply #39 on: February 09, 2009, 09:06:29 AM »
Sorry I've not responded earlier - been away all weekend.

Only last (hopefully) attempt at understanding:

  • EVAL and QUOTE area actually as I described earlier
  • SETQ recognises its first term as a "target," so does nothing with it, but evaluates the second term and assigns that to the "target," hence (SETQ a (+ 1 2)) it ignores anything that might be in a, assigning the result of (+ 1 2) to it instead
  • SET, the tricky one!  SET tries to figure out what, if anything, it's target means, and uses that in its computations, hence (SET a (+ 1 2)) would check to see whether or not anything had been assigned to a.  If nothing has been assigned to a, it calculates (+ 1 2) and assigns that to a.  If a already has a value, it spills out an error.
  • Basically, SET is used for doing stuff to variable names, whereas SETQ is for doing stuff to the value of variables
dJE
===
dJE

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Declaring variables in nested functions
« Reply #40 on: February 09, 2009, 09:34:29 AM »
Quote
hence (SET a (+ 1 2)) would check to see whether or not anything had been assigned to a.  If nothing has been assigned to a, it calculates (+ 1 2) and assigns that to a.  If a already has a value, it spills out an error.

No, set evaluates the first argument, then :
If the evaluation result is not valid symbol, an error occur.
Quote
Commande: (setq a nil b 12)
12
Commande: (set a (+ 1 2))
; erreur: type d'argument incorrect: symbolp nil
Commande: (set b (+ 1 2))
; erreur: type d'argument incorrect: symbolp 12
If the evaluation result is valid symbol, the evaulation of the second argument is bounded to the symbol.
Quote
Commande: (setq c 'b)
B
Commande: (set c (+ 1 2))
3
Commande: !c
B
Commande: !b
3
Speaking English as a French Frog

Daniel J. Ellis

  • Swamp Rat
  • Posts: 811
Re: Declaring variables in nested functions
« Reply #41 on: February 26, 2009, 09:01:29 AM »
As an addendum to this, I've just found myself in one final relevant (to my original query) situation:

Code: [Select]
(defun c:rtest (/)
(GETSET "0-fdp-h-blocks")
)

(DEFUN getset ( layer / )
(SETQ
ss (SSGET "x" (LIST (CONS 8 layer)))
ssl (SSLENGTH ss)
cnt 0
) ;SETQ
)

My question is, does "layer" need declaring as a variable, and it so, where.

I don't think it *does* need declaring, and will simply pop out of existence after "getset" finishes running, but I wanted to check...

dJE
===
dJE

JohnK

  • Administrator
  • Seagull
  • Posts: 10625
Re: Declaring variables in nested functions
« Reply #42 on: February 26, 2009, 09:22:26 AM »
`layer' is an ARGUMENT not a variable in that snip-it.

I'm going to try and find an article i think will help you; brb.
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

JohnK

  • Administrator
  • Seagull
  • Posts: 10625
Re: Declaring variables in nested functions
« Reply #43 on: February 26, 2009, 09:27:42 AM »
Read and study that pdf; it will help you. There is quite a bit of information between the lines so to speak.
http://www.theswamp.org/index.php?topic=5203.0
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

Daniel J. Ellis

  • Swamp Rat
  • Posts: 811
Re: Declaring variables in nested functions
« Reply #44 on: February 27, 2009, 02:56:05 AM »
`layer' is an ARGUMENT not a variable in that snip-it.

That's what I thought, I wanted to check though, thanks :)

Read and study that pdf; it will help you. There is quite a bit of information between the lines so to speak.
http://www.theswamp.org/index.php?topic=5203.0

I have actually read this before, in fact implimenting some of it has lead, in part, to some of the questions that caused me to start this thread.

(I have a generic "extract assoc value" function, for example)

dJE
===
dJE

JohnK

  • Administrator
  • Seagull
  • Posts: 10625
Re: Declaring variables in nested functions
« Reply #45 on: February 27, 2009, 08:38:34 AM »
<snip>

I have actually read this before, in fact implimenting some of it has lead, in part, to some of the questions that caused me to start this thread.

(I have a generic "extract assoc value" function, for example)

dJE

Well, that's good that its leading you down a path of questions but its bad that its causing you confusion; maybe i should rewrite it?

TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org