TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: steve.carson on April 14, 2016, 12:57:31 PM

Title: Using vlr-sysvar-reactor to update an Xrecord
Post by: steve.carson on April 14, 2016, 12:57:31 PM
Hi,

The company I work for (referred to as "MN") has various lisp files to help standardize our drawings. We call them "MN Tools". One of these creates an Xrecord that stores the dimension layer name that gets set to current when adding dimensions. We recently upgraded to 2016 and now there is the system variable "dimlayer". I added a simple setvar to our Tools to update the dimlayer system variable if the user sets or changes the dimension layer through our tools. But I thought it would be nice if the Xrecord would update if the user changed the dimension layer saved in the system variable (through the ribbon or whatever). So I took my first plunge into Reactors and created the code below. It works as I would like, but have read that reactors are sensitive to things, so was hoping somebody with reactor experience could take a look and see if there are any potential problems.

Code - Auto/Visual Lisp: [Select]
  1. ;;Reactor to change the MN dimension layer if the user changes the Autocad system variable "dimlayer"
  2. ;;
  3. ;;Written by: Steve Carson
  4. ;;
  5. ;;04/07/2016
  6. ;;
  7. ;;Thanks to www.afralisp.net for the lesson on Reactors
  8.  
  9.  
  10.  
  11.  
  12.  
  13. ;************************************************************************************
  14. ;Initialize the Reactor
  15.  
  16.  
  17.  
  18. (vlr-sysvar-reactor "Dimlayer Changed" '((:vlr-sysVarChanged . MN:dimlayerchanged)))
  19.  
  20.  
  21. ;************************************************************************************
  22.  
  23.  
  24. ;Callback function
  25.  
  26. (defun MN:dimlayerchanged (calling-reactor Command-Info / DL Xrec)
  27.  
  28.  
  29. (if (= (car Command-Info) "DIMLAYER")
  30.  
  31.     (progn
  32.      
  33.      (setq DL (getvar "dimlayer"))
  34.  
  35.      (if (dictsearch (namedobjdict) "DWGPROPS")
  36.  
  37.        (dictremove (namedobjdict) "DWGPROPS")
  38.  
  39.      )
  40.  
  41.      (setq Xrec (list (cons 0 "XRECORD")
  42.  
  43.                       (cons 100 "AcDbXrecord")
  44.  
  45.                       (cons 1 "DWGPROPS COOKIE")
  46.  
  47.                       (cons 300 (strcat "dimlayer=" DL))
  48.  
  49.                  );list
  50.  
  51.       );setq
  52.  
  53.       (dictadd (namedobjdict) "DWGPROPS" (entmakex Xrec))
  54.  
  55.  
  56.     );progn
  57.    
  58.  
  59. );if
  60.  
  61.  
  62.  
  63.  
  64.  
  65.  
  66. );Callback Defun
  67.  

Note that I will update the header to reflect any assistance received in this thread.


Thanks in advance,

Steve
Title: Re: Using vlr-sysvar-reactor to update an Xrecord
Post by: Lee Mac on April 14, 2016, 01:18:26 PM
Here are some suggestions:
Code - Auto/Visual Lisp: [Select]
  1. (   (lambda nil
  2.             (if (= "Dimlayer Changed" (vlr-data rtr)) (vlr-remove rtr))
  3.         )
  4.         (vlr-sysvar-reactor "Dimlayer Changed" '((:vlr-sysvarchanged . MN:dimlayerchanged)))
  5.     )
  6. )
  7. (defun MN:dimlayerchanged ( rtr arg / dim )
  8.     (if (and (= (strcase (car arg)) "DIMLAYER") (setq dim (getvar 'dimlayer)))
  9.         (progn
  10.             (dictremove (namedobjdict) "DWGPROPS")
  11.             (dictadd    (namedobjdict) "DWGPROPS"
  12.                 (entmakex
  13.                     (list
  14.                        '(000 . "XRECORD")
  15.                        '(100 . "AcDbXrecord")
  16.                        '(001 . "DWGPROPS COOKIE")
  17.                         (cons 300 (strcat "dimlayer=" dim))
  18.                     )
  19.                 )
  20.             )
  21.         )
  22.     )
  23.     (princ)
  24. )
Title: Re: Using vlr-sysvar-reactor to update an Xrecord
Post by: roy_043 on April 14, 2016, 01:53:26 PM
@ Steve:
Why do you remove the dictionary instead of just the xrecord?
What is the meaning of (1 . "DWGPROPS COOKIE")?
It seems that a "DWGPROPS" dictionary was used in older versions of AC. Is it wise to use that name for a custom application?
Title: Re: Using vlr-sysvar-reactor to update an Xrecord
Post by: steve.carson on April 14, 2016, 02:22:34 PM
Thanks for the suggestions, Lee!
I've learned some new things, just by going through them. I understand that lambda creates an anonymous function, but what is the purpose of using it here?


Thanks,

Steve

Title: Re: Using vlr-sysvar-reactor to update an Xrecord
Post by: steve.carson on April 14, 2016, 02:37:16 PM
@ Steve:
Why do you remove the dictionary instead of just the xrecord?
What is the meaning of (1 . "DWGPROPS COOKIE")?
It seems that a "DWGPROPS" dictionary was used in older versions of AC. Is it wise to use that name for a custom application?

Hi Roy,

I made the reactor emulate what our current tools do when setting the dimension layer. In all honesty, our tools are old and could definitely benefit from some optimization. When trying to add to, or modify something in our lisp files I sometimes feel like an electrician dealing with this  :laugh: :


Title: Re: Using vlr-sysvar-reactor to update an Xrecord
Post by: JohnK on April 14, 2016, 03:21:09 PM
Thanks for the suggestions, Lee!
I've learned some new things, just by going through them. I understand that lambda creates an anonymous function, but what is the purpose of using it here?


Thanks,

Steve

Pure trickery I tell you!

Code - Auto/Visual Lisp: [Select]
  1. (   (lambda nil
  2.             (if (= "Dimlayer Changed" (vlr-data rtr)) (vlr-remove rtr))
  3.         )
  4.         (vlr-sysvar-reactor "Dimlayer Changed" '((:vlr-sysvarchanged . MN:dimlayerchanged)))
  5.     )
  6. )

He could have just as easily typed, without the lambda, like this:

Code - Auto/Visual Lisp: [Select]
  1.     (if (= "Dimlayer Changed" (vlr-data rtr)) (vlr-remove rtr)))
  2. (vlr-sysvar-reactor "Dimlayer Changed" '((:vlr-sysvarchanged . MN:dimlayerchanged)))

No, seriously though (joking aside), one would type the lambda to give a cleaner "copy-paste thing" or just signify that "you can make a function out of this code and call it what you want" or for any number of different reasons.

The
Code - Auto/Visual Lisp: [Select]
  1. (lambda ( / ) ...
is an anonymous function.

The
Code - Auto/Visual Lisp: [Select]
  1. ( (lambda ( / ) ...
is like saying: execute this anonymous function (note the extra paren).
Title: Re: Using vlr-sysvar-reactor to update an Xrecord
Post by: steve.carson on April 14, 2016, 04:19:39 PM
Thanks John!

Yeah the extra parenthesis threw me for a minute, so I did a test at the command line of
Code - Auto/Visual Lisp: [Select]
  1. (lambda nil (/ 6 2))
and sure enough, it didn't return "3", so I tried
Code - Auto/Visual Lisp: [Select]
  1. ((lambda nil (/ 6 2)))
and that returned 3.



Steve
Title: Re: Using vlr-sysvar-reactor to update an Xrecord
Post by: JohnK on April 14, 2016, 05:10:30 PM
Thanks John!

Yeah the extra parenthesis threw me for a minute, so I did a test at the command line of
Code - Auto/Visual Lisp: [Select]
  1. (lambda nil (/ 6 2))
and sure enough, it didn't return "3", so I tried
Code - Auto/Visual Lisp: [Select]
  1. ((lambda nil (/ 6 2)))
and that returned 3.



Steve

Extra credit: what is the difference between "(lambda nil" and "(lambda (/)"?
Title: Re: Using vlr-sysvar-reactor to update an Xrecord
Post by: Lee Mac on April 14, 2016, 05:37:27 PM
Thanks for the suggestions, Lee!
I've learned some new things, just by going through them. I understand that lambda creates an anonymous function, but what is the purpose of using it here?

You're welcome Steve -

As John notes above, the use of lambda here is not strictly necessary, but I use it purely to add some structure to the code (since the enclosed expressions are part of the same block of code performing a particular task, but don't warrant declaring a separately named defun); also, temporary variables used by such expressions would be declared local to the lambda function to avoid unnecessary globals.
Title: Re: Using vlr-sysvar-reactor to update an Xrecord
Post by: JohnK on April 14, 2016, 05:48:38 PM
> local to the lambda
But remember to localize; recall the "lexical scoping" discussions I've given.
Title: Re: Using vlr-sysvar-reactor to update an Xrecord
Post by: ChrisCarlson on April 15, 2016, 08:08:07 AM
Thanks John!

Yeah the extra parenthesis threw me for a minute, so I did a test at the command line of
Code - Auto/Visual Lisp: [Select]
  1. (lambda nil (/ 6 2))
and sure enough, it didn't return "3", so I tried
Code - Auto/Visual Lisp: [Select]
  1. ((lambda nil (/ 6 2)))
and that returned 3.



Steve

Extra credit: what is the difference between "(lambda nil" and "(lambda (/)"?

Shooting from the hip here but does  (lambda nil) mean it accepts no arguments and saves no variables but (lambda (/)) will?
Title: Re: Using vlr-sysvar-reactor to update an Xrecord
Post by: JohnK on April 15, 2016, 08:38:53 AM
Extra credit: what is the difference between "(lambda nil" and "(lambda (/)"?
Shooting from the hip here but does  (lambda nil) mean it accepts no arguments and saves no variables but (lambda (/)) will?

Nice but, sorry, no.
(lambda nil ...
is the same as
(lambda ( / ) ...

No arguments and no localization's (the use of `nil' is essentially just shorthand). I don't think it's a good idea to use it in teaching cases because it is no different then the long hand version but it can/does tend to obfuscate a little (users shouldn't just take code and cut and paste; they should know and understand the aspects of the code they're given and even a harmless thing like that can cause confusion for some).

However, that's not to say that using `nil' is bad; the `nil' is a great trick and most definitely worth using sometimes. For example (posting some old code of mine found on a USB) this is some code to create an anonymous function for later execution:

Code - Auto/Visual Lisp: [Select]
  1. (defun hook (func)
  2.   ;; hook
  3.   ;;
  4.   ;; This function will take an argument and turn it into a
  5.   ;; lambda expression to evaluate. (You can assign to a variable
  6.   ;; and exec it at a later time if you wish.)
  7.   ;;
  8.   ;; Ex: (hook '(+ 1 2))
  9.   ;;     > ((LAMBDA nil (+ 1 2)))
  10.   ;;    
  11.   ;; Ex 2: (setq zoom
  12.   ;;            (hook '(vla-zoomextents
  13.   ;;                (vlax-get-acad-object))))
  14.   ;;     > ((LAMBDA nil (vla-ZoomExtents (vlax-get-acad-object))))
  15.   ;;
  16.   ;; By: John K
  17.   ;;    (inspired by something I saw in one of
  18.   ;;     Vladimir Nesterovsky's procedures.)
  19.   ;;
  20.   (list (cons 'lambda (cons nil (list func)))) )


Title: Re: Using vlr-sysvar-reactor to update an Xrecord
Post by: steve.carson on April 15, 2016, 12:02:08 PM
Thanks for the responses Guys.


(lambda nil ...
is the same as
(lambda ( / ) ...


That's what I always thought, but searched anyways thinking maybe there was some obsure tiny difference at the processor level (or something else way over my head).

My search turned up nil (pun intended).



Steve
Title: Re: Using vlr-sysvar-reactor to update an Xrecord
Post by: JohnK on April 15, 2016, 12:17:30 PM
lol