Help understanding global variables vs local variables

Help understanding global variables vs local variables

Alex_Hughes6GQ7S
Participant Participant
597 Views
6 Replies
Message 1 of 7

Help understanding global variables vs local variables

Alex_Hughes6GQ7S
Participant
Participant

Hello, and thanks in advance for reading this. I'm a CAD drafter teaching himself a little AutoLISP between projects at work. I don't have any real coding experience prior to this, and am learning mostly by searching through documentation and using the blessed AfraLISP guides. I have already done some searching through these forums as well. Specifically, this link back from 2018 didn't do much to help me, and only served to confuse me more.

 

I'm having some trouble understanding the difference between global and local variables. I thought a variable being global meant that if it was changed in a function call, it would stay changed if used again outside that function. And a local variable would be discarded after that function call was finished.

 

I've got some code to explain my problem:

 

(defun testMe ()
  
  (setq l1 (list 1 2)
        l2 (list 2 3)
  )
  
  (princ l2)
  
  (defun addPoints (l1 l2)
    ;Adds the values of two points together
    ;l1 = first point
    ;l2 = second point
    (setq a (+ (car l1) (car l2))
          b (+ (cadr l1) (cadr l2))
          l2 (list a b)
    )
  )
  
  (princ (addPoints l1 l2))
  (princ l2)
  (princ)
)

addPoints just takes two points, and adds them together. To my understanding, l1 and l2 are global here (not defined following a / ). At the end of the addPoints function, l2 is set to the sum of the two points. Line 19 prints this to verify it. 

 

Because l2 is global, I would expect the value it is set inside of the addPoints function to be retained even after the addPoints function has ended. So after running (testMe), I should receive an output of (l2 prior to call)(l2 after call)(l2 after call), or (2 3)(3 5)(3 5).

 

What I'm actually getting is (2 3)(3 5)(2 3). I can see that while l2 is being successfully called during the addPoints function, the value isn't being saved afterwards, despite the addPoints function passing the value to the (princ) command. This is how I'd expect the code to run if I had defined it as (addPoints ( / l1 l2)) So, I think I'm missing something about how global vs local variables work.

 

I don't want to be rude or presumptuous, but I'd prefer responses that directly address my misunderstanding here, as opposed to asking why I didn't do this in a different way or offering another method (unless what I'm thinking is just completely wrong, of course). In this exact example, I'm sure there are plenty of workarounds and other ways to do this, but I'd like to be able to use functions to redefine more complicated items (like drawing elements) in the future, and being able to call (modifyElement(element value)) instead of having to step around with repeated (assoc)'s and (subst)'s would make my life a lot easier, and my code more readable.

 

Thanks again for your time!

0 Likes
Accepted solutions (2)
598 Views
6 Replies
Replies (6)
Message 2 of 7

ВeekeeCZ
Consultant
Consultant
Accepted solution

See THIS first.

 

(defun addPoints (l1 l2

l1 and l2 are arguments! And from the link above:

 

The symbols used as arguments are defined in the argument list before the local variables. Arguments are treated as a special type of local variable; argument variables are not available outside the function. You cannot define a function with multiple arguments of the same name.

 

Message 3 of 7

Alex_Hughes6GQ7S
Participant
Participant

So if I wanted to change the start point of a line entity, I can't do something like this:

(defun moveLineStart (line destination)
  ;line = line to move
  ;destination = desired new coordinates of line start point
  (subst
    (cons (car destination) (cadr destination))
    (assoc 10 line)
    line
  )
)

(I know entities aren't this easy to modify, but I think you understand what I'm trying to do here)

 

Instead I'd have to use the substitute chunk of code every time? That works, but it just adds a lot more text to the code, and I like to keep my code as short and easy to parse as I can

0 Likes
Message 4 of 7

Kent1Cooper
Consultant
Consultant

The start point entry in entity data needs to start with a 10, but you can tack that right onto the front, without splitting the destination coordinates into separate entries.  And you then need to modify that entity to have its substituted entity data list take effect:

 

(defun moveLineStart (line destination)
  ;line = entity data list of line to move [not just entity name]
  ;destination = desired new coordinates of line start point

  (entmod
    (subst
      (cons 10 destination)
      (assoc 10 line)
      line
    ); subst

  ); entmod
)

Kent Cooper, AIA
0 Likes
Message 5 of 7

johnyDFFXO
Advocate
Advocate
Accepted solution

Sure you can. But for the arguments, I would prefer to use different names than the original variables. 

 

(defun moveLineStart (ent pnt / def)
  ;ent = line to move
  ;pnt  = desired new coordinates of line start point
  
  (setq def (entget ent))
  (entmod (subst (cons 10 pnt)
		 (assoc 10 def)
		 def))
  ent ; make sure it returns ename
  )

 

 

 

Or more typically:

 

(defun MainProgram ( / _moveLineStart _moveLineEnd)
  
  (defun _moveLineStart (d p)
    (subst (cons 10 p)   ;; subst returns definition
	   (assoc 10 d)
	   d))
  
  (defun _moveLineEnd (d p)
    (subst (cons 11 p)    ;; subst returns definition
	   (assoc 11 d)
	   d))
  
  ; --------------------
  
  (if (setq ent (car (entsel "\nSel the line: ")))
    (while (and
	     (setq pt1 (getpoint "\nNew beginning: "))
	     (setq pt2 (getpoint "\nNew end: "))
	     )
      (progn
	(setq def (entget ent))
	(setq def (_moveLineStart def pt1)) ; save the return of your sub
	(setq def (_moveLineEnd   def pt2))
	(entmod def)
))))

 

Message 6 of 7

Kent1Cooper
Consultant
Consultant

@Alex_Hughes6GQ7S wrote:

.... I'd have to use the substitute chunk of code every time? ... it just adds a lot more text to the code, and I like to keep my code as short and easy to parse as I can


For that, consider alternative ways to achieve the same thing that may be available.  For example, in this case, if line is an entity name, not an entity data list:

 

(defun moveLineStart (line destination)
  ;line = line entity name [not entity data list] to move
  ;destination = desired new coordinates of line start point
  (setpropertyvalue line "StartPoint" destination)
)

 

Kent Cooper, AIA
0 Likes
Message 7 of 7

Sea-Haven
Mentor
Mentor

A couple of suggestions.

 

 

(setq pt3  (mapcar '+ pt1 pt2) )  ;  adds 2 points

(setq pt3 (mapcar '(lambda (x) (/ x 2.0)) pt3)  ;   divide by 2
(setq mp (mapcar '* (mapcar '+ p1 p3) '(0.5 0.5))) ; add & divide

 

 

You only need 1 function not 2 for lengthen, if you select the entity near an end can check which end you picked so for your task lengthen that end. An example.

 

(defun swapends (ent / obj)
(setq pt3 (cadr ent))
(setq obj (vlax-ename->vla-object (car ent)))
(setq start (vlax-curve-getstartPoint obj))
(setq end (vlax-curve-getEndPoint obj))
(setq d1 (distance pt3 end))
(setq d2 (distance pt3 start))
(if (< d1 d2)
(progn
(setq temp end)
(setq end start)
(setq start temp)
)
)
(princ)
)

 

 

 

0 Likes