Author Topic: What is the best way to localise or set variable to NIL  (Read 8649 times)

0 Members and 1 Guest are viewing this topic.

jaydee

  • Guest
What is the best way to localise or set variable to NIL
« on: August 12, 2011, 12:19:42 AM »
Hi.
I have these sub function call from a main function.
The reason i have these sub function is that they will be called to many main functions.
Its quite straight forward if these subfunctions only contain a few variables, i can simply localise them, but not sure if this is the best way to go if each subfunctions contain roughly 100 or more varibles.What im doing at the moment is to have a subfunction (SetVar2Nil) at the end of the main function.

My question is no matter how you look at it, its a long list of variable.
Is there a short cut to set these vars to nil/or localise them properly.

Thankyou, any advice will be much appriciated.

Code: [Select]
(defun c:fun1 ()
(subfunc1)
(subfunc2)
etc....etc
(SetVar2Nil)
)

Code: [Select]
(defun subfunc1 ()
(setq a "AAA")
(setq b "BBB")
(setq c "CCC")

;Roughly 100 or more (setq's)
)

Code: [Select]
(defun SetVar2Nil ()
(setq
a nil
b nil
c nil
.
.
.
aaa nil
bbb nil
)
)
« Last Edit: August 12, 2011, 01:30:12 AM by jaydee »

BlackBox

  • King Gator
  • Posts: 3770
Re: What is the best way to localise or set variable to NIL
« Reply #1 on: August 12, 2011, 12:50:34 AM »
I'm not sure I understand why you would need to change so many variables to perform a LISP operation, but this should work:

Code: [Select]
(defun subfunc1 ( / A B C)
  (setq A "AAA")
  (setq B "BBB")
  (setq C "CCC")
  ;; ... More
  )
« Last Edit: August 12, 2011, 12:55:58 AM by RenderMan »
"How we think determines what we do, and what we do determines what we get."

jaydee

  • Guest
Re: What is the best way to localise or set variable to NIL
« Reply #2 on: August 12, 2011, 01:29:26 AM »
thankyou Renderman.
I know how to localise variables and those variables  in the subfunctions (only a few) will be passed on to the main functions.

Yes by default i should localise in the main functions (defun c:func1 ( / a b c .........etc)
But my question is there a better way of doing this.

I read up something about foreach member atom and not fully understand about these work and suspected it could be something to do with setting varibles.

Well people reading this post might be curious why i have so many variable.
It in a plot routine i have which i pre-set a varible for each
.pc3
.ctb
paper size
Plot size
etc.

So in my lisp command "-PLOT" will end up with all variablesinstead of "Y" "N" "N" etc.

and for a large office, there will be many combinations.




« Last Edit: August 12, 2011, 01:35:50 AM by jaydee »

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: What is the best way to localise or set variable to NIL
« Reply #3 on: August 12, 2011, 04:00:37 AM »
It's again one of those situations where I'd use a list variable to store all those values. Makes life simpler in the long run.

About the set to nil using a foreach, you're probably referring to the atoms-family list of all variable/defun names. The problem with simply running through that is you can't just go and nil them all - most of them are all the defuns you'd use in other situations (including all the built-in defuns). So you'd need to check their names against a list of names (or perhaps a wildcard).

So you'd either need to use the extract list as strings and then use the read and eval to get to their actual symbols. Or use the vl-symbol-name to extract each to a string for checking.

IMO once you've done all that you've probably done way more typing than simply setting each as localized.

Alternatively you could save a list from atoms-family before setting your variables. Then after completing use the member/vl-position to check which atoms are new in the new call to atoms-family. Though this is going to be quite slow (since there's 100's of atoms already without any extras from your own routines), not to mention you're using quite a lot of RAM to store the names. Much simpler to just "combine" the related settings into a list, you could either then use nth or make your list "readable" and turn it into an association list. E.g:
Code: [Select]
;; Using nth
(defun subfunc1 (/ )
  (setq SettingList
    '("AAA"
      "BBB"
      "CCC"
    )
  )
)
(nth 1 SettingList) ;Returns the 2nd item --> "BBB"

;; Using assoc
(defun subfunc1 (/ )
   (setq SettingList
     '((A . "AAA")
       (C . "CCC")
       (B . "BBB")
     )
   )
)
(cdr (assoc 'C SettingList)) ;Returns the "CCC", list need not be in order
And then to nil them all (if you don't localize the SettingList variable) :
Code: [Select]
(setq SettingList nil)
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

pBe

  • Bull Frog
  • Posts: 402
Re: What is the best way to localise or set variable to NIL
« Reply #4 on: August 12, 2011, 04:11:11 AM »
This what comes in mind.

http://www.theswamp.org/index.php?topic=37689.msg427195#msg427195

The topic there is about finding all floating variables. you can do the next step by assigning nil for every item on that list (result)

BlackBox

  • King Gator
  • Posts: 3770
Re: What is the best way to localise or set variable to NIL
« Reply #5 on: August 12, 2011, 06:28:27 AM »
I had originally posted this, but decided against it as I still feel that you should localize, but FWIW:

Code: [Select]
(vl-load-com)
(foreach var '(A B C)
  (vl-catch-all-apply 'set (list var nil))
)

Edit: Typo! I typed strcat in lieu of set <<Slaps forehead>>
« Last Edit: August 12, 2011, 08:48:30 AM by RenderMan »
"How we think determines what we do, and what we do determines what we get."

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: What is the best way to localise or set variable to NIL
« Reply #6 on: August 12, 2011, 06:59:44 AM »
RM ... I'm unsure I understand what's supposed to happen there. Aren't you possibly trying the following?
Code: [Select]
(mapcar '(lambda (var) (set var nil)) '(A B C))
The problem with the codes as linked to by pBe ... that's going to remove all global vars which aren't the "built-in" stuff. So anywhere you actually wanted a global (e.g. saving a default value for user entry) this is going to be removed. And if your code expects a global to already exist - there's going to be an error. And then "just-for-fun" if ADesk (ever) decides to "update" A/VLisp the new functions / variables need to be incorporated into your routine.

I'm definitely with you on the score of localizing as much as possible! As for having a long list of vars, I'll reiterate: Use a list variable, you can even then much more easily save that variable to a file for later re-load, thus also allowing to much more easily share the different versions between co-workers. Having several separate vars for such just becomes messy to work with, the code becomes enormous with very little re-usability.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
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.

BlackBox

  • King Gator
  • Posts: 3770
Re: What is the best way to localise or set variable to NIL
« Reply #8 on: August 12, 2011, 08:51:11 AM »
RM ... I'm unsure I understand what's supposed to happen there. Aren't you possibly trying the following?
Code: [Select]
(mapcar '(lambda (var) (set var nil)) '(A B C))

:?... Totally a typo on my part. Code corrected. :sigh:
"How we think determines what we do, and what we do determines what we get."

Lee Mac

  • Seagull
  • Posts: 12914
  • London, England
Re: What is the best way to localise or set variable to NIL
« Reply #9 on: August 12, 2011, 10:06:41 AM »
After reading the first post, this comes to mind:

http://www.theswamp.org/index.php?topic=39081.0

dgorsman

  • Water Moccasin
  • Posts: 2437
Re: What is the best way to localise or set variable to NIL
« Reply #10 on: August 12, 2011, 10:32:29 AM »
I'm not seeing any arguments or return values in the original functions posted, which may be part of the problem.  Since all variables won't be needed everywhere, keep the scope of each variable as small as possible.

Generally speaking, if I have more than a dozen or two local variables its either time to use a list or split the function into separate routines.
If you are going to fly by the seat of your pants, expect friction burns.

try {GreatPower;}
   catch (notResponsible)
      {NextTime(PlanAhead);}
   finally
      {MasterBasics;}

JohnK

  • Administrator
  • Seagull
  • Posts: 10642
Re: What is the best way to localise or set variable to NIL
« Reply #11 on: August 12, 2011, 01:33:35 PM »
Oh, fun.


> creating a list of variable names.

Let's go low tech on this one.
Code: [Select]
gawk -F"setq" "{print $2}" mylispfile.lsp | gawk "{print $1}" >> mylispfile.lsp
or from within Vim.
Code: [Select]
:!gawk -F"setq" "{print $2}" % | gawk "{print $1}" >> %
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

JohnK

  • Administrator
  • Seagull
  • Posts: 10642
Re: What is the best way to localise or set variable to NIL
« Reply #12 on: August 12, 2011, 02:40:24 PM »
BTW, I thought I should add a link to a nice tutorial on AWK.
http://www.theswamp.org/index.php?topic=8476.0
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

jaydee

  • Guest
Re: What is the best way to localise or set variable to NIL
« Reply #13 on: August 12, 2011, 09:56:14 PM »
Thankyou All comments on my post.
theres quite a fair bit of info to absorb.

Another question. Is there any different between.

localise (/ a b c)
and
(setq a nil b nil c nil)

My understanding is that localise will clear the var from memory.
and (setq a nil) is just simply provide a nil value to the symbol, meaning the variable still there but with NO values.


irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: What is the best way to localise or set variable to NIL
« Reply #14 on: August 13, 2011, 04:57:59 AM »
Yes there is a difference. Localizing will "encapsulate" the variable(s) in the scope where it's made. E.g. look at the following:
Code: [Select]
(defun PrintABC (heading / var)
  (princ "\n\n")
  (princ heading)
  (princ "\n------------------------------------------------")
  (foreach var '(a b c d)
    (princ "\n\t")
    (princ var)
    (princ " = ")
    (princ (eval var))
  )
  (princ)
)

(setq a "A global"
      b "B global"
      c "C global"
      d "D global"
)

(defun testlocal (/ b d testlocal-sub)
  (PrintABC "As testlocal starts")
 
  (defun testlocal-sub ( / c d)
    (PrintABC "As testlocal-sub starts")
    (setq a "A in testlocal-sub"
          b "B in testlocal-sub"
          c "C in testlocal-sub"
          d "D in testlocal-sub"
    )
    (PrintABC "As testlocal-sub finishes")
  )
 
  (setq a "A in testlocal"
        b "B in testlocal"
        c "C in testlocal"
        d "D in testlocal"
  )
 
  (PrintABC "Just before testlocal-sub is called")
  (testlocal-sub)
  (PrintABC "As testlocal finishes")
)

(PrintABC "Just before testlocal is called")
(testlocal)
(PrintABC "After testlocal completes")
Running this code you get the following:
Code: [Select]
Just before testlocal is called
------------------------------------------------
   A = A global
   B = B global
   C = C global
   D = D global

As testlocal starts
------------------------------------------------
   A = A global
   B = nil
   C = C global
   D = nil

Just before testlocal-sub is called
------------------------------------------------
   A = A in testlocal
   B = B in testlocal
   C = C in testlocal
   D = D in testlocal

As testlocal-sub starts
------------------------------------------------
   A = A in testlocal
   B = B in testlocal
   C = nil
   D = nil

As testlocal-sub finishes
------------------------------------------------
   A = A in testlocal-sub
   B = B in testlocal-sub
   C = C in testlocal-sub
   D = D in testlocal-sub

As testlocal finishes
------------------------------------------------
   A = A in testlocal-sub
   B = B in testlocal-sub
   C = C in testlocal
   D = D in testlocal

After testlocal completes
------------------------------------------------
   A = A in testlocal-sub
   B = B global
   C = C in testlocal
   D = D global
Firstly, all localized variables are initialized to nil. E.g. in the 2 cases where the defun starts you can see the localized versions contain nil

As you can see the b & d retained their original values at the end since they were localized in the testlocal function. It's as if inside the function there's new versions of b & d, and thus any setq's to them won't affect their previous versions.

Same happens inside the testlocal-sub, where c & d are localized. Only now you see that b gets altered for the localized version inside the testlocal function, thus its value in the "As testlocal finishes" position shows the value as it's been assigned in the testlocal-sub function.

If you simply nil'ed them all the globals would also be nil, as would all the values shown in "As testlocal finishes".

So here you can see the effect of nesting localizations. Sometimes you'd want to edit a value in the surrounding function, in such case you'd not localize the variable in the sub-function (as done with the b variable). Only when you want the value to be retained after all the defuns are complete would you NOT localize - as done with the a variable.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.