ksperopoulos Posted February 6, 2014 Posted February 6, 2014 I have a single lisp file with multiple programs in it. All of these programs use the same subfunctions. Instead of placing these subfunctions within each program, can I just place them once in the lisp file? Quote
Snownut Posted February 6, 2014 Posted February 6, 2014 Sort of depends on how you are defining & calling the programs if they are defined ie: "defun c:foo ( / )", essentially adding them as commands to your cad program all sub-functions need to be defined within them or called is some other manner. You could place all the sub-functions in their own main function ie "defun c:_subs (subfun / )", where subfun would represent the actual sub-function you want to run, then call from the main function accordingly. There are other methods to build / compile the functions within VLIDE that you may want to investigate. Quote
Jef! Posted February 6, 2014 Posted February 6, 2014 like this? (defun c:function1 () (subfunctionx) ... );end defun (defun c:function2 () (subfunctionx) ... );end defun ;-----sub functions---- (defun subfunctionx () ... )end defun of course! Quote
jdiala Posted February 6, 2014 Posted February 6, 2014 I have a single lisp file with multiple programs in it. All of these programs use the same sub-functions. Instead of placing these sub-functions within each program, can I just place them once in the lisp file? No you can't. You must load the sub-function separately from your lisp and make it a global function. If you run the lisp which holds the sub-function and didn't purge it from the code then it will be global. (defun C:test ( / subfunction ) ;will release the sub-function from memory. ;; if sub-function isn't declared then it will be global ;; but this routine must be called first before the other ;; routines can call it. (subfunction) (functions) ) by doing this one below (subfunction) ; by making this global any of you routine can call this function (defun C:test2 () (subfunction) ) (defun C:test3 () (subfunction) ) This is the reason why we declare our *error* function to be local. Quote
ksperopoulos Posted February 6, 2014 Author Posted February 6, 2014 The way Jef! describes above is what I am hoping to do. If I localize each subfunction within each program so they are not global, I should be good to go right? Quote
ksperopoulos Posted February 6, 2014 Author Posted February 6, 2014 I'm lost. I thought I was doing it correctly, but like most times....I was wrong. Help please! (defun c:TESTALIAS ( / *error* massoc ent elist typ laypipe layalias laycolor alias) (while (setq ent (entsel "\nSelect CADmep object: ")) (progn (setq elist (entget (car ent)) typ (cdr (assoc 0 elist)) ) (if (= typ "MAPS_SOLID") (progn (setq laypipe (cdr (assoc 8 elist)) layalias (strcat laypipe "-TEXT") laycolor (cdr (assoc 62 (tblsearch "LAYER" laypipe))) alias (nth 4 (massoc 300 elist)) ) (if (null (tblsearch "LAYER" layalias)) (progn (entmake (list '(0 . "LAYER") '(100 . "AcDbSymbolTableRecord") '(100 . "AcDbLayerTableRecord") (cons 2 layalias) '(70 . 0) (cons 62 laycolor) '(6 . "Continuous") '(290 . 1) '(370 . 25) ) ) (setvar "clayer" layalias) ) (setvar "clayer" layalias) ) (command "mleader" pause pause alias) ) (prompt "\nNot a CADmep object.") ) ) ) (princ) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun *error* (msg) (if (not (member msg '("Function cancelled" "quit / exit abort"))) (princ (strcat "\nError: " msg)) ) (princ) ) (defun massoc ( key lst / item ) (if (setq item (assoc key lst)) (cons (cdr item) (massoc key (cdr (member item lst)))) ) ) Quote
Jef! Posted February 6, 2014 Posted February 6, 2014 Is it for the line alias (nth 4 (massoc 300 elist))? If so, the way to recall a subfunction, you must put it in parentheses. alias (nth 4 ((massoc) 300 elist)) because as is, since you declared a local var named massoc, and not putting massoc in parentheses, it uses the local variable massoc instead of the sub function. Don'T mix variable and sub function. Also, you don't have to declare a subfunction. And 1 question, is your massoc subfunction trying to refer itself? (defun massoc ( key lst / item ) (if (setq item (assoc key lst)) (cons (cdr item) ([b]massoc[/b] key (cdr (member item lst)))) ) ) Quote
ksperopoulos Posted February 6, 2014 Author Posted February 6, 2014 Is it for the line alias (nth 4 (massoc 300 elist))? yes ... since you declared a local var named massoc... I didn't think I was using massoc as a variable. I was trying to use it as a symbol for naming the subfunction. By placing it in the parentheses after the function's name "TESTALIAS", it localizes it to that function only right? And 1 question, is your massoc subfunction trying to refer itself? Yes. I got this from LeeMac from an earlier post today. Quote
Jef! Posted February 6, 2014 Posted February 6, 2014 ok, got it. Nevermind my previous post, (massoc 300 elist) is between parenthesis, and 300 and elist are 2 arguments. so alias is (nth 4 (massoc 300 elist)) or the 5th element of the list returned from sub function "massoc provided with arguments 300 & elist". No parentheses are missing there. My bad. I didn't think I was using massoc as a variable. I was trying to use it as a symbol for naming the subfunction. By placing it in the parentheses after the function's name "TESTALIAS", it localizes it to that function only right?To my knowledge, adding anything after (defun c:TESTALIAS ( / is declaring a variable local... but jdiala say otherwise and makes me doubt. To be honest, I never declared any sub functions, and I'll follow that thread closely, because I don't think it is making a difference. I might be totally wrong but as I see it you declared a variable massoc that don't exist so it don't change anything. (Or maybe you need to declare (massoc) instead of massoc... could that be done ? ) . To totally make the devils advocate, if you add a massoc variable, how could you declare local both a subfunction and a variable local? My head hurts^^ Next thing, lets say you do manage to declare the subfunction so it is "released from memory".. doing so would it not be useless?; When you make a sub-function, and want to communicate its results, you must pass it using a global variable, or make the sub so it returns the value.. when you call a sub-function that don't use global vars but returns the result, from what I know the value is returned but not stored, and every time you recall a sub it is reevaluated. Perhaps I misunderstood something. This thread is most interesting.... By trying to much to analyse Lee Mac's work, we might ending up with brain damage, (but its worth it!) =D I hope I didn't mislead anyone here.. Quote
BIGAL Posted February 7, 2014 Posted February 7, 2014 In a software package we use sub functions all over the place these were simply loaded at start up then they are available for any program, you are right about local and global variables check the part of the defun (ans / x y) ans is passed x y are local. Also they do not have to be C: defuns can be basicly any name the C: implies can be called from keyboard, I am sure others will elaboarte more. Quote
cwake Posted February 7, 2014 Posted February 7, 2014 To paraphrase Bill Kramer from one of his books on LISP "In the context of VisualLISP, everything is a symbol. When a symbol is used to hold a value, it is called a variable. When a symbol is used to hold a function definition list, it is called a function" So yes, when you localise a variable (read that as "symbol") it has the same effect regardless of what it holds. I'm trying to upload some screenshots from the VLIDE that shows the contents of the three symbols after loading your LISP and after invoking it to run but the forum isn't playing ball. So I'll try to mimic that in text: After loading the routine: *ERROR* = # C:TESTALIAS = # MASSOC = # which shows the three functions (User SUBR's) as good to go. But after invoking the routine: *ERROR* = nil C:TESTALIAS = # MASSOC = nil The two symbols that were localised display as nil. So yes, localising symbols that contain functions will make them unavailable to use. Which means if you want the functions to be available to other functions, leave your routine as it is but remove the function names from the list of localised symbols. Alternatively, define the functions within the outer brackets of the main defun, like this. (defun c:TESTALIAS ( / *error* massoc ent elist typ laypipe layalias laycolor alias) ;------------------------------------------------------------------ (defun *error* (msg) (if (not (member msg '("Function cancelled" "quit / exit abort"))) (princ (strcat "\nError: " msg)) ) (princ) ) ;------------------------------------------------------------------ (defun massoc ( key lst / item ) (if (setq item (assoc key lst)) (cons (cdr item) (massoc key (cdr (member item lst)))) ) ) ;------------------------------------------------------------------ (while (setq ent (entsel "\nSelect CADmep object: ")) (progn (setq elist (entget (car ent)) typ (cdr (assoc 0 elist)) ) (if (= typ "MAPS_SOLID") (progn (setq laypipe (cdr (assoc 8 elist)) layalias (strcat laypipe "-TEXT") laycolor (cdr (assoc 62 (tblsearch "LAYER" laypipe))) alias (nth 4 (massoc 300 elist)) ) (if (null (tblsearch "LAYER" layalias)) (progn (entmake (list '(0 . "LAYER") '(100 . "AcDbSymbolTableRecord") '(100 . "AcDbLayerTableRecord") (cons 2 layalias) '(70 . 0) (cons 62 laycolor) '(6 . "Continuous") '(290 . 1) '(370 . 25) ) ) (setvar "clayer" layalias) ) (setvar "clayer" layalias) ) (command "mleader" pause pause alias) ) (prompt "\nNot a CADmep object.") ) ) ) (princ) ) Quote
Jef! Posted February 7, 2014 Posted February 7, 2014 (edited) Very interesting cwake. Thanks for sharing! "In the context of VisualLISP, everything is a symbol. When a symbol is used to hold a value, it is called a variable. When a symbol is used to hold a function definition list, it is called a function"So yes, when you localize a variable (read that as "symbol") it has the same effect regardless of what it holds. After loading the routine: *ERROR* = # C:TESTALIAS = # MASSOC = # which shows the three functions (User SUBR's) as good to go. But after invoking the routine: *ERROR* = nil C:TESTALIAS = # MASSOC = nil The two symbols that were localized display as nil. So yes, localizing symbols that contain functions will make them unavailable to use. when you localize a variable (read that as "symbol") it has the same effect regardless of what it holds.That statement has something suspicious tho, because it seems that it don't have the same effect depending if the symbol stores a variable or a function. If we take for instance this simple routine (defun c:test ( / x) (setq x 33) ) Then we define a symbol to contain a global variable x with a different value, lets say 22 , then run the test routine. The "local" symbol containing the variable x from the function will store 33, then be dismissed. Still, the symbol containing the global variable x defined outside will remain and keep its value. Command: (setq x 22)22 Command: test 33 Command: !x 22 Maybe it is because no massoc if defined within the main command (where it is declared local), but another simple test shows that symbols react differently when they store a variable or a sub function. Lets try another test, defining the symbol x as a local variable, and without redefining it in the routine. (defun c:test ( / x) (princ "hello") ) Command: setq x 22)22 Command: test hello"hello" Command: !x 22 same result, the symbol defined containing the global variable x remains. ...while the symbol containing a sub function (already defined) will lose its definition if a function is executed having the said symbol declared as a local variable. Unless there is something I neglected to take into consideration, I have to disagree with that statement "when you localise a variable (read that as "symbol") it has the same effect regardless of what it holds" Very very interesting thread. @ksperopoulos: If you remove massoc from the local symbols of c:TESTALIAS, does it work? Edited February 7, 2014 by Jef! Quote
cwake Posted February 7, 2014 Posted February 7, 2014 Hi Jef, Thanks for your comments. I'm probably not great at explaining these things. Would it have helped if I had added in my explanation that once the main function C:TESTALIAS had completed you will again see the symbols *ERROR* and MASSOC bound to the relevant functions? as in: *ERROR* = # C:TESTALIAS = # MASSOC = # It is only while the function is running (and those symbols are "localised" in the context of that function being executed) that the symbols appear to lose their definition. Meanwhile, outside of the function those variables are still present and holding their global value. Which is kind of what you alluded to when you gave the examples in your last post. Quote
ksperopoulos Posted February 7, 2014 Author Posted February 7, 2014 @ksperopoulos: If you remove massoc from the local symbols of c:TESTALIAS, does it work? Yes. When I remove massoc from the local variables, the program works like intended. To be honest, I never declared any sub functions... Do you not localize the *error* subfunction when you have it in your code? Quote
Jef! Posted February 7, 2014 Posted February 7, 2014 Cwake you are great at explaining! Sometimes, even if some concepts or context need further clarification to be fully understood, it don't mean that the one explaining is not good at it. LISP and VisualLISP are complex, and it is not always obvious to grasp everything. It all make sense now. If you declare a local symbol, like with all my examples, you can use any already defined symbol without affecting them. If you declare a local symbol within a function and recall this symbol, it will look for the local variant. If by the time you use it is not defined there come the problems. (defun c:test ( / x) (princ x) ) Command: (setq x 22)22 Command: TEST nilnil Command: Command: !x 22 Bill Kramer was right: So symbols really react the same wether they contain a variable or a function. Do you not localize the *error* subfunction when you have it in your code? localize the *error* symbol? When you do, I bet you define it within the first lines of the function? Well.. I have still have much to learn. I read about, and learn functions as I need them, and I discover new stuff, concepts and functions every day. I didn't even grasp the concept of the *error* function yet. It is on my to do list and one of my next milestone. Quote
ksperopoulos Posted February 7, 2014 Author Posted February 7, 2014 LeeMac has some good reading on error handling on his website. He makes it so that even I can understand it (at least I think I understand it)! I'm waiting for Lee to come out with a book on this stuff. I will buy his first copy! Quote
Recommended Posts
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.