Jump to content
Hudson

Keeping track of variables function to function day to day

Recommended Posts

Hudson

I've managed to get the basics of my program working well enough that I now know I'm not wasting my time ;)

 

It's become apparent that I need to keep track of many variables and use them not only in various functions, but from day to day preferably.

 

So I'm thinking that I need to start writing things to a file.

 

Is this the right reaction, or am I just asking for a lot of pain?

 

Thanks,

 

Andrew

Share this post


Link to post
Share on other sites
Lee Mac

Variables should be local to a function, and you should not need to worry about them after the function has completed.

 

It is the Global Variables you should watch out for :)

Share this post


Link to post
Share on other sites
Hudson
Variables should be local to a function, and you should not need to worry about them after the function has completed.

 

It is the Global Variables you should watch out for :)

 

I think the biggest problem I had getting my head around global variables is I didn't understand where they were declared..

 

I can just setq away and as long as it's not defined as a local it's global, right?

 

how about when I close the drawing and reload it?

 

Elementary stuff I know.. but for some reason I'm not getting something here :oops:

Share this post


Link to post
Share on other sites
Lee Mac

A while back I wrote a tutorial on localising variables, but it is yet to be approved by the board :)

 

Here is the copy/paste version:

 

What is the Purpose of the Brackets after (defun cxx... ?

 

This is a question that many people have when they first start to write code in LISP, and there is much uncertainty surrounding the issue.

 

Some Background on "defun"

 

Start AutoCAD and type VLIDE at the command line to open the Visual LISP Editor. Go to File > New File and type "defun". The text will turn blue indicating that the Editor recognises it as a function. Double-click on the function and click on the help icon on the toolbar (beige speech bubble).

 

This will bring up the VLA help on the "defun" function.

 

When reading the help article, notice the purpose of the brackets: everything before the "/" is an argument (data required for the program to run) and everything after it is a variable, (a symbol with a value bound to it).

 

Note: Arguments must be declared within these brackets, otherwise the program will cease to function. Arguments are symbols used to represent input data that the user must supply in order to make the function perform.

 

However, if the Function has no arguments (most, if not all, functions called from the command line have no arguments), then the code can have an empty set of brackets next to the defun. But there are certain conseqences from doing this.

 

Why Use the Brackets?

 

 

This practice is called "localising" the variables, (basically because when within the brackets, the variables are referred to as "local variables" as opposed to "global variables")

 

When localising a variable, it is declared as a variable of the function, and, after the function has completed, any values bound to it will be set to nil, hence the variable will now become just a symbol.

 

Why is this important?

 

 

There are many points:

 

Take the case in which two functions use the same symbols to represent variables. Without declaring any variables, after the function has completed, the variables are still holding their values - until they are redefined - which they may not be. This can cause all sorts of problems, as a value from the first program may be inadvertently used in the second.

 

Another major problem occurs when looping within a function and a variable is referring to itself.

 

Take this code for example:

 

(defun c:test  ()
  (vl-load-com)
  (foreach x  '(1 2 3 4 5)
    (setq aList (cons x aList)))
  (alert (vl-princ-to-string aList))
(princ)) 

The above is a simple code to illustrate the point of localising variables. It will take each number in the list: (1 2 3 4 5) in turn and merely add it to the cumulative list.

 

Hence we will expect a return of the reversed list (why would it be reversed?):

 

(5 4 3 2 1)

And this should be what is returned.

 

Now run the code a second time...

 

We receive the result:

 

(5 4 3 2 1 5 4 3 2 1) 

This is where the variable "aList" has held its value after the function has completed. Hence, when the function is re-invoked, the numbers in the list are added to the already populated output list. Which is not the result we desire as it is not consistent.

 

Now, try this code:

(defun c:test  (/ aList)
  (vl-load-com)
  (foreach x  '(1 2 3 4 5)
    (setq aList (cons x aList)))
  (alert (vl-princ-to-string aList))
(princ))

When running the above a second time, notice that the return is the same every time - hence we can rely on the consistency of the program.

 

Global Variables

 

 

It is sometimes desirable for a variable to hold its value over the course of a drawing session, for example, storing a default option for a program for every time it is invoked. These are called "global variables", and should not be included in the brackets next to the function definition (defun).

 

However, as mentioned above, these have the ability to clash with other functions which are using the same symbols to define variables, so its better if variable names are original - perhaps using semi-colons, with the function name as the prefix, so there is very little chance of duplication (see the example below):

 

Here is an example code that uses global variables:

 

(defun c:glob  (/ temp)
  (vl-load-com)
  (alert (strcat "Value of glob:def before \"OR\":\n" (vl-princ-to-string glob:def)))
  (or glob:def (setq glob:def "Hello"))
  (setq temp (getstring (strcat "Type Something <" glob:def ">: ")))
  (or (eq "" temp) (setq glob:def temp))
  (alert (strcat "Value of temp: \n" (vl-princ-to-string temp)))
  (alert (strcat "Value of glob:def:\n" (vl-princ-to-string glob:def))) 
(princ)) 

The phrases that include the function "vl-princ-to-string" are merely alerting the value of the variables, (just to illustrate a point).

 

Experiment with the above code, re-invoke it a few times over, and the effect of the global variable will be seen.

 

But, notice that the variable "temp" is still localised within the brackets after the function definition, as this is still a local variable. Also, that the global variable is defined as glob:def, using the function name glob as the prefix and an arbitrary suffix.

 

This just about covers most of the information on local and global variables, but if you have any further questions, just post a thread in the forums and we'd be more than happy to help out.

Share this post


Link to post
Share on other sites
gile

Hi,

 

The ways I use store datas depends their accessibility:

During one session

- within a function: local variables (setq function)

- within the drawing : global variables (setq function)

- to populate datas to every opened document: vl-propagate or use the blackboard (vl-bbset/vl-bbref)

 

how about when I close the drawing and reload it?
- within the drawing: ldatas, xdatas, xrecords, dictionaries (vlax-ldata* functions for ldatas, entmod or vla-* functions for the other ones)

- datas which have to be accessible from any drawing can be stored in the registry (setenv/getenv or vl-registry* functions)

Share this post


Link to post
Share on other sites
JohnM

You should learn all the different ways to write data to a file, xdata , xrecord registry entrees, then determine which one best suits your programs needs.

First all variables need to be nil when the program ends to keep them from interfering with other variables in other programs.

If you learn to write data to other locations you will not need to worry about global variables although I do admit there is a place and time for them.

I would suggest that you spend some time and create a lisp file just for writing and reading data then just include the file when you compile to a vlx.

I have one file that has various functions to write to different kinds of locations.

Set each function up with arguments to receive the data file name and path or whatever the function requires. And in your program just make a call to the function passing the info to it like (setq wf (my_writefile data filename path) ) this calls a function called my_writefile and passes 3 pieces of data to it. Then at the end of the my_writefile function have it pass back something to tell you that the function wass successful or not so you can deal with it accordingly.

Setting these functions up in a separate file to be included will save you tons of time with other programs that require their use.

Share this post


Link to post
Share on other sites
TimSpangler

Look at this topic:

 

http://www.theswamp.org/index.php?topic=1445.msg18109#msg18109

 

Download the atoms family browser (thanks Micheal)

 

Run your program in a new session then run the browser, this will help you determine what you have that is floating out there unattended. This is great tool for developers, especially if you have a large program that need some serious policing of variables....

 

Send all check to Micheal....

Share this post


Link to post
Share on other sites
Lee Mac

Good point Tim - I use that as well :)

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...