• Industries
  • Products
  • Buy
  • Services & Support
  • Communities
  • Visual LISP, AutoLISP and General Customization

    Reply
    Distinguished Contributor
    Posts: 277
    Registered: ‎10-10-2007

    Variable Scope

    240 Views, 20 Replies
    09-27-2012 06:38 AM

    I've had a quick look around the forums but cannot find anything on variable scope......

     

    How do I define a global variable where I can access from two different lisp functions?

     

    For example, something along the lines of:

    (vl-load-com)
    
    [var x]
    
    (defun func2 ()
      (setq x "ABC")
      (princ)
    )
    
    (defun func1 ()
      (setq x "DEF")
      (princ)
    )

     

    Thanks

     

     

    Please use plain text.
    *Expert Elite*
    Kent1Cooper
    Posts: 4,058
    Registered: ‎09-13-2004

    Re: Variable Scope

    09-27-2012 07:05 AM in reply to: dbrblg

    dbrblg wrote:

    .....

    How do I define a global variable where I can access from two different lisp functions?

     

    For example, something along the lines of:

    ....
    (defun func2 ()
      (setq x "ABC")
      (princ)
    )
    
    (defun func1 ()
      (setq x "DEF")
      (princ)
    )

    ....


    If you want to be able to set or change the variable x from within more than one function, and have either function replace any value set into that variable by the other, then what you have will work, not listing x as a localized variable within either one.  If you want each of the functions to have its own value in x without affecting its value for the other function, then it can't be global -- you would need to either localize it within each function:
     
    (defun func1 (/ x)

    ....

     

    [which would mean each function would need to make any use of x before it finishes], or it would need to have a different name in each function, such as x1 and x2.

     

    Or am I misunderstanding what you're trying to do?

    Kent Cooper
    Please use plain text.
    *Pro
    M_Hensley
    Posts: 1,574
    Registered: ‎12-11-2003

    Re: Variable Scope

    09-28-2012 04:00 AM in reply to: dbrblg

    You could save data in the registry and access it later from anther lisp by using SETENV and GETENV functions.

    Please use plain text.
    Distinguished Contributor
    Posts: 277
    Registered: ‎10-10-2007

    Re: Variable Scope

    09-28-2012 04:08 AM in reply to: dbrblg

    Thanks for your suggestions. 

     

    I'm giving up with lisp for the time being...may eventually get back to it when I have found some patience.

     

    I cannot believe lisp still exists in Autocad:smileyfrustrated:

    Please use plain text.
    *Expert Elite*
    Kent1Cooper
    Posts: 4,058
    Registered: ‎09-13-2004

    Re: Variable Scope

    09-28-2012 06:17 AM in reply to: dbrblg

    dbrblg wrote:

    .... 

    I'm giving up with lisp for the time being....


    Don't give up yet.  I admit it's not clear to me what you mean by the phrase "variable scope" [for example, is "variable" there a noun or an adjective?].  If you can describe in more detail what you want to accomplish, or how you want to use the variable(s), there may well be something here already, or someone may come up with an easy solution, or it may be appropriate to something like [in the case of your sample settings] the USERS1-through-USERS5 System Variables, or something.

    Kent Cooper
    Please use plain text.
    Distinguished Contributor
    Posts: 277
    Registered: ‎10-10-2007

    Re: Variable Scope

    09-28-2012 06:38 AM in reply to: dbrblg

    Hi Kent,

     

    I'm trying to do something really quite simple....well, or so I thought anyway :smileysurprised:

     

    With reference to my variable scope, I suspect I used a generic name to describe what I want.  It is a little ambiguous but I also suspect the terminology in lisp may be different from that of other languages.  

     

    Basically what I am trying to achieve is to switch on certain points when a certain command is activated and then return them to what they were before when the command ends.

     

    For example I have this:

    (vl-load-com)
    
    (defun c:StartReactor ()
      (or *Reactor_Command*
          (setq *Reactor_Command*
    	     (vlr-lisp-reactor
    	       "My command reactor "
    	       '((:vlr-lispWillStart . Callback:LispWillStart)
    		 (:vlr-lispEnded . Callback:LispEnded)
    		)
    	     )
          )
      )
      (prompt "\n  >>  Command reactor loaded ")
      (princ)
    )
    
    (defun Callback:LispWillStart (rea cmd)
    ;;;  (alert (strcat "Lisp started: " (car cmd)))
      (if (eq (car cmd) "(C:AEFOOTPRINT)")
        (progn
          (prompt (car cmd))
          (setq pointMode (getvar 'PDMODE))
          (prompt (strcat "\n pointMode Variable: " pointMode "\n PDMODE Variable: " (itoa(getvar 'PDMODE))))
          (setvar "PDMODE" 99)
          (prompt (strcat "\n PDMODE Variable: " (itoa(getvar 'PDMODE))))
        )
      )
      (princ)
    )
    
    (defun Callback:LispEnded (rea cmd)
    ;;;  (alert "Lisp ended")
      (if (/= pointMode nil)
        (progn
          (prompt (strcat "\n PDMODE Variable: " (pointMode)))
          (setvar 'PDMODE pointMode)
        )
    (prompt (strcat "\n pointMode Variable is nil"))
      )
      (princ)
    )
    
      (defun c:StopReactor ()
        (if	*Reactor_Command*
          (progn
    	(vlr-remove *Reactor_Command*)
    	(setq *Reactor_Command* nil)
          )
        )
        (prompt "\n  >>  Command reactor stopped ")
        (princ)
      )
    
    
    (defun *error* (x) (vl-bt))

     As you can see there are a lot of prompts and alerts in there.  The debugger in Autocad is primitive to say the least (or it's me not grasping it fully) and i'm finding it a nightmare to debug properly.

     

    The idea with the variable is there is one (called pointMode) which is shared between the LispWillStart and LispEnded functions which holds the state of PDMODE before it is changed and then allows it to be restored.

     

    Thats the idea anyway.  I'm getting so many errors it's quite hard to describe where to start, hence I thought a break would be in order. 

     

    Make of this what you will :smileyhappy: it's not particuarly 'tidy' or efficient shall we say....but then again, lisp is not my first language, but you may have guessed that!!

     

     

    Please use plain text.
    *Expert Elite*
    Kent1Cooper
    Posts: 4,058
    Registered: ‎09-13-2004

    Re: Variable Scope

    09-28-2012 10:09 AM in reply to: dbrblg

    dbrblg wrote:

    .... what I am trying to achieve is to switch on certain points when a certain command is activated and then return them to what they were before when the command ends.

     

    For example I have this:

    ....
          (setq pointMode (getvar 'PDMODE))
          (prompt (strcat "\n pointMode Variable: " pointMode "\n PDMODE Variable: " (itoa(getvar 'PDMODE))))
          (setvar "PDMODE" 99)
          (prompt (strcat "\n PDMODE Variable: " (itoa(getvar 'PDMODE))))
    ....
     
    ....
      (if (/= pointMode nil)
        (progn
          (prompt (strcat "\n PDMODE Variable: " (pointMode)))
          (setvar 'PDMODE pointMode)
        )
    (prompt (strcat "\n pointMode Variable is nil"))
    ....

    ....The idea with the variable is there is one (called pointMode) which is shared between the LispWillStart and LispEnded functions which holds the state of PDMODE before it is changed and then allows it to be restored.

    ....


    I haven't worked with reactors, but I notice a couple of things....

     

    The pointMode variable will hold an integer, so you're going to need to convert that to a string to include it in a prompt.  After setting it to match PDMODE, you have a prompt that is telling the values of both, which will be the same.  And after setting PDMODE to 99, you're digging the value out of that, when you already know that's what it is.  Maybe something like this in place of the parts quoted above.

     

    ....
          (setq pointMode (getvar 'PDMODE))
          (prompt

            (strcat

              "\nCurrent PDMODE System Variable, saved in pointMode Variable: "

              (itoa pointMode)

              ".\nSetting PDMODE to 99."

            ); strcat

          ); prompt
          (setvar "PDMODE" 99)
    ....
     
    ....
      (if pointMode ; [easier than checking whether it's not equal to nil]
        (progn ; then
          (prompt (strcat "\nResetting PDMODE Variable to " (itoa pointMode)))
          (setvar 'PDMODE pointMode)
        ); progn
        (prompt "\n pointMode Variable is nil"); else [without unneeded (strcat)]

      ); if
    ....

    Kent Cooper
    Please use plain text.
    Distinguished Mentor
    Moshe-A
    Posts: 675
    Registered: ‎09-14-2003

    Re: Variable Scope

    09-28-2012 02:50 PM in reply to: dbrblg

    Hi,

     

    from my experience (of many years) there is no problem with global (or local variables) in AutoLISP

    and i know some other languages that i can compare to. the rules are the same.

     

    here is a fix i made for you especially look at (lprompt) functon which let to prompt any message

    without the need to convert int/real to string.

     

    Moshe

     

     

    (defun lprompt (args / a)
     (foreach a args (princ a))
    )
    
    
    (vl-load-com)
    (setq LISP-REACTOR-DATA "My command reactor")
    
    (defun c:StartReactor ()
      (or *Reactor_Command*
          (setq *Reactor_Command*
    	     (vlr-lisp-reactor
    	       LISP-REACTOR-DATA
    	       '((:vlr-lispWillStart . Callback:LispWillStart)
    		 (:vlr-lispEnded     . Callback:LispEnded    )
    		)
    	     )
          )
      )
      
      (prompt "\n>>Command Reactor is enabled now.")
      (princ)
    )
    
    (defun Callback:LispWillStart (rea cmd)
    ;;;  (alert (strcat "Lisp started: " (car cmd)))
      (if (and (eq (vlr-data rea) LISP-REACTOR-DATA)
               (eq (car cmd) "(C:AEFOOTPRINT)")
          )
        (progn
          (lprompt (list "\n" (car cmd) "\n"))
          (setq pointMode (getvar 'PDMODE))
          (lprompt (list "start: pointMode Variable: " pointMode "\nstart: PDMODE Variable: " (getvar 'PDMODE) "\n"))
          (setvar 'PDMODE 99)
          (lprompt (list "start: PDMODE Variable: " (getvar 'PDMODE) "\n"))
        )
      )
    
      (princ)
    )
    
    (defun Callback:LispEnded (rea cmd)
    ;;;  (alert "Lisp ended")
      (if (and (eq (vlr-data rea) LISP-REACTOR-DATA)
    	   (/= pointMode nil)
          )
       (progn
        (lprompt (list "ended: PDMODE Variable: " pointMode "\n"))
        (setvar 'PDMODE pointMode)
       )
       (prompt "\nended: pointMode Variable is nil.\n")
      )
    
      (princ)
    )
    
    (defun c:StopReactor ()
     (if *Reactor_Command*
      (progn
       (vlr-remove *Reactor_Command*)
       (setq *Reactor_Command* nil)
      )
     )
      
     (prompt "\n>>Command Reactor is Disabled now")
      
     (princ)
    )
    
    
    (defun C:AEFOOTPRINT ()
     ; only invokes (Callback:LispWillStart)
     (princ)
    )
    
    

     

    Please use plain text.
    *Pro
    scot-65
    Posts: 1,927
    Registered: ‎12-11-2003

    Re: Variable Scope

    09-28-2012 03:11 PM in reply to: dbrblg

    dbrblg wrote:

    How do I define a global variable where I can access from two different lisp functions? 


    Global variables, for current session (until AutoCAD is closed), I refer to as "Gremlins".

    I have a few of these written in several of my programs.

    The structure I use to name this variable is "USER_xxx", where "xxx" is the routine name.

     

    To create this Gremlin, do not declare the variable in the defun section, as you showed.

    (defun c:MyABC ( / a b c)

     (setq a 1)

     (setq USER_MyABC "True")

     (princ)

    )

     

    USER_MyABC can now be seen by other programs, however "a" cannot.

     

    It would be wise to declare this global variable outside the realm of the programs that access this.

    Suggest declaring this inside any interface file (LSP, MNL, etc.), or in S::smileyfrustrated:TARTUP itself.

    Suggest having long names with underscore(s), in case other third-party programs happen

    to employ the same variable name as his gremlin. Yes, it has happened to me early on when

    I inherited our menu system with these known bugs.

    Suggest inside the program that will reference this variable to do a check first, then apply

    a default value if not found: (if (not USER_MyABC) (setq USER_MyABC "True")).

     

    Where SDI=0, and you switch drawings, can the next drawing see USER_MyABC?

    I do not know this answer. But to be safe, you can use the SETCFG/GETCFG, and

    VL-REGISTRY-READ/VL-REGISTRY-WRITE methods to access this across drawings.

     

    Hope this helps.

     

    ???

     

    Please use plain text.
    Distinguished Mentor
    Moshe-A
    Posts: 675
    Registered: ‎09-14-2003

    Re: Variable Scope

    09-28-2012 03:33 PM in reply to: scot-65

    Hi Scot-65,

     

    (vl-bb-set) & (vl-bb-ref)

     

    never used them my self but seems they can provide some solution?

     

    moshe

     

     

     

    Please use plain text.