Author Topic: Declaring variables in nested functions  (Read 25673 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: 10626
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: 10626
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: 10626
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