vlax-put-property usage

David Kozina

Usenet Archive
Joined
Sep 6, 2000
Messages
310
Reaction score
0
There were some comments made a few weeks ago regarding the utter lack of necesity for the *entire* set of vla- functions - and that that entire set could be reduced to 3 vlax- functions: vlax-invoke-method, vlax-get-property, and vlax-put-property.

So - after reviewing my code for vla- functions, I noticed that, with respects to the vla-put- property functions, once I replaced them with their vlax- equivalents, they looked like a prime target for further optimization...

IOW, once I changed this code:
(vla-put-Color _obj acByBlock)
(vla-put-Layer _obj "0")
(vla-put-Linetype _obj "BYBLOCK")
(vla-put-LineWeight _obj acLnWtByBlock)

to this:
(vlax-put-property _obj 'Color acByBlock)
(vlax-put-property _obj 'Layer "0")
(vlax-put-property _obj 'Linetype "BYBLOCK")
(vlax-put-property _obj 'LineWeight acLnWtByBlock)

it seemed that now it could be reduced further, with a small 'wrapper' function, PutProperties, which goes like so:

; applies new property values to an object
(defun PutProperties
(_obj ; object to apply new property values to Property_alst ; assoc list of new ('Property . Value) dotted pairs / ; ) ; begin ; ...process property pairs (mapcar (function (lambda (Property_dp) (vlax-put-property _obj (car Property_dp) (cdr Property_dp) ) );_end lambda );_end function ; begin list Property_alst ; end list );_end mapcar ; end );_end defun

However, if I try to work with an actual list of dotted pairs:
(PutProperties
_obj
'(('Color . acByBlock)
('Layer . "0")
('Linetype . "BYBLOCK")
('Lineweight . acLnWtByBlock)
)
)

AutoCAD revolts under the strain. Why?
(I've tried various combinations of a literal quoted association list, to no avail.) I imagine it's a pretty basic oversight on my part- but I can't see it. Can a quoted list be used here?

Yet, using list and cons does work:
(PutProperties
_obj
(list
(cons 'Color acByBlock)
(cons 'Layer "0")
(cons 'Linetype "BYBLOCK")
(cons 'Lineweight acLnWtByBlock)
)
)

It just isn't as compact as I was hoping for.

Finally, is this basically a good/sound idea or not?

Have you found a more effective/efficient way to use vlax-put-property in your code? Would error-trapping be a good thing to add to the PutProperties routine, or would it just bog it down needlessly?

Comments would be appreciated.

Best regards,
David Kozina
 
David,
If you packed it any tighter, you would need C-4 to unpack it. (for other humans).
Bob
 
acByBlock and acLnWtByBlock are symbols that
must be evaluated.

Not sure what the point to the "wrappers" are, but
I prefer to have code that is more expressive in
nature (e.g., individual calls to vla-put-xxxxx).

The fact that you can reduce all ActiveX method
calls and property references to only 3 functions
doesn't necessarily mean that doing so serves a
good purpose. In this case, it doesn't really,
since it makes code harder to read and understand,
without making it the least bit faster.

On the other hand, here is a case where a wrapper
can do wonders for Visual LISP ActiveX programming:

;; Universal nested property getter
;;
;;
;; Syntax:
;;
;; (vla-get <proplist>)
;;
;;
;; Where <proplist> '(PropertyName|IndexKey ...))
;;

(defun vla-get (proplist)
(if (and proplist (atom proplist))
(vlax-get-property
(vlax-get-acad-object)
proplist
)
(vla-get-aux (vlax-get-acad-object) proplist)
)
)

(defun vla-get-aux (obj proplist / value result)
(cond
( (not proplist) obj)
(t (setq value
(if (member (type (car proplist)) '(int str))
(vlax-invoke-method obj 'Item (car proplist))
(vlax-get-property obj (car proplist))
)
)
(setq result (vla-get-aux value (cdr proplist)))
(if (and (cdr proplist)
(eq (type value) 'vla-object)
)
(vlax-release-object value)
)
result
)
)
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

It's too much typing for me to fully explain what the
above functions do, but this should make it perfectly
clear:

Command: (vla-get '(ActiveDocument ActiveLayer Name))
"0"

Command: (vla-get '(ActiveDocument Layouts 1 Name))
"Layout2"

[You need at least 1 object in Modelspace for this]:

Command: (vla-get '(ActiveDocument Modelspace 0 EntityName))
"AcDbCircle"

Command: (vla-get '(ActiveDocument ActiveLayout))
#<VLA-OBJECT IAcadLayout 01bc0924>

The really interesting part, is that all intermediate
results which are VLA-OBJECTS are also released via
calls to (vlax-release-object)
 
I've found that (vlax-invoke), (vlax-get), and (vlax-put) work the best most of the time and avoid the tedium of dealing with safearrays and variants. BUT, you can't use them all the time. A prime example is the GetBoundingBox method where you have to supply the quoted symbol names for the return values of MinPoint and MaxPoint.

(vlax-invoke Object 'GetBoundingBox 'MinPoint 'Maxpoint) doesn't set the symbols MinPoint or MaxPoint, whereas (vla-GetBoundingBox Object 'MinPoint 'Maxpoint) will.

Your idea of "wrapping" may or may not be advantageous. Judge for yourself by counting the number of evaluations any function performs. Then do a time-test.
Learning is fun.

Practice makes perfect, or at least gets closer.
 
Just a side note regarding comments you've
recieved:

If performance were so important as some seem
to think, to the extent that they can use it
as justification for obsfucated and extremely
difficult to read code, then consider using a
proramming language that does not execute like
molasses in January.

The "programmer-in-a-vacume" mentality that
some independent, renagade consultants who do
not have to routinely deal with other formally
educated programmers have, often misleads them
into beliving they can get away with writing
obsfucated code. However, that is not the rule,
it is the exception.

If you're serious about programming and expect
to collaborate or work with others who are,
writing code in the "let me make them scratch
their heads" style of coding that some routinely
exhibit here, will win you 0 friends in the
world of formally educated, qualfied software
engineering professionals.
 
David,
Tony explained why yours didn't work and demonstrated a nice wrapper function. Here is another flavor (just for fun).

;|begin vla-get.lsp----------------------------------------- An ActiveX wrapper function inspired by Tony Tanzillo. D. C. Broad, Jr. 1/4/2004
Function: Universal nested property getter
Format: (vla-get <property list>)
NOTE: Property list must be in order of specific to general
Examples:
(vla-get '("door" blocks activedocument)) ;;assuming block door (vla-get (list 'count *model*)) ;where *model* is the modelspace (vla-get nil) ;returns application (vla-get '(color 0 modelspace activedocument)) ;assuming mspace obj (vla-get '(name activelayer activedocument))
-----------------------------------------------------|; (defun vla-get (lst) (cond ((null lst) (vlax-get-acad-object)) ((= (type (car lst)) 'vla-object) (car lst)) ((member (type (car lst)) '(int str)) (vlax-invoke-method (vla-get(cdr lst)) 'item (car lst))) ((vlax-get-property (vla-get (cdr lst)) (car lst))))) ;;-------------------------------------------end vla-get.lsp
 
Doug - thanks for the flattery. Aside from requiring
the elements in the list to be backwards; requiring the object parameter to be in the list; and not bothering to release intermediate vla-objects, how does this differ from/improve on what I posted?
 
1)Reorganizing the list backwards eliminated the
necessity for 2 functions to implement the recursion.
This seemed simpler and more readable
but that is up to others (including you) to decide.
2)An object is not required to be in the list but is
allowed to be in the list, so, theoretically, it is more generalized. If an object is already known, there is no need to look it up again from the root object.
3)IMO, objects which are not bound to symbols
do not need to released. Since the only symbol was
the list argument and since that would be automatically garbage collected it seemed unnecessary to release the object binding. (Without storing the intermediate vla-objects, there was no mechanism to release them.) My understanding is that unless the object is bound to a global symbol, it does not require release. What do you think?
4)If the property list is more than 1 item long, the
revised version seems to operate faster although
I doubt anyone would notice.

Thanks again for your demonstration.
 
Doug Broad said:
1)Reorganizing the list backwards eliminated the
necessity for 2 functions to implement the recursion.
This seemed simpler and more readable
but that is up to others (including you) to decide.

Sounds like you've got the cart in front of the horse
here. It's not about the readability of the api function, but the readability of the calls made to it that are the issue. I can see any compelling reason why one would sacrifice the latter to serve the former.

Using the same outer-to-inner syntax used in most other languages (like VB for example) is the primary objective to start with. The backwardness of what you're doing only to eliminate the need for two functions to do the recursion is IMHO, self-defeating.
2)An object is not required to be in the list but is
allowed to be in the list, so, theoretically, it is more generalized.

I think You're assuming that my (vle-get) is the only
entry point. One can just as easily use (vle-get-aux)
without (vle-get) when the root object is something other than the Application, and since they may already have that object in a variable, it makes sense to express it as a seperate argument, rather than requring them to add it to the list.
3)IMO, objects which are not bound to symbols
do not need to released.

I don't agree. Not releasing an AcadEntity can lead to
problems (the BREAK a CIRCLE into an ARC scenario).
 
In response,
1)List order quirky
Point taken. The list order is a weakness of the revision.
2)Aux function has its own uses
Point taken. I would have prefered the single function but can see your point. I also better understand your point of requiring the object in the list wheras your vla-get-aux keeps them separate.
3)Not releasing objects causes problems.
Agree. After testing, my function causes problems
if requesting the color of a circle that is later broken into an arc whereas yours does not. This is a serious weakness.

A call to (gc) would have been necessary to reset
mine in the circle/arc scenario, wheras it would not be required with your function. Although mine could be fixed, it would have no advantages over yours and still have the reverse list order problem.

Using any version to return a vla-object also causes
problems if that object is not released later by the
calling function or (gc) done.

Thanks for your response and for your functions.
 
Tony Tanzillo said:
acByBlock and acLnWtByBlock are symbols that
must be evaluated.

Doh! Of course.

Not sure what the point to the "wrappers" are, but
I prefer to have code that is more expressive in
nature (e.g., individual calls to vla-put-xxxxx).

The fact that you can reduce all ActiveX method
calls and property references to only 3 functions
doesn't necessarily mean that doing so serves a
good purpose. In this case, it doesn't really,
since it makes code harder to read and understand,
without making it the least bit faster.

Well, for me, using the vlax- functions actually *does* make the code easier to read and understand - since the code actually *says* that I'm using a 'method' or working with a 'property'. I can see that the vla- functions result in more abbreviated code - but the vlax- functions seem to be more consistently written - which makes it easier for me to follow. I don't know why - perhaps it was/is just the primary learning curve, but trying to figure out and use the vla- functions has been a major headache for me. After the vlax- functions were brought to my attention, I thought, 'Hey, for some reason, this is *much* simpler for me to write.' Just my own experience.

As for the little PutProperties function - it seemed like a fair way to use a 'dxf'-like (yet more readable than dxf group code numbers) association list when setting object properties. So there I go - make the code less abbreviated by using the vlax- functions, and then try to abbreviate the result. What can I say? :)

On the other hand, here is a case where a wrapper
can do wonders for Visual LISP ActiveX programming:

;; Universal nested property getter
;;
;;
;; Syntax:
;;
;; (vla-get <proplist>)
;;
;;
;; Where <proplist> '(PropertyName|IndexKey ...))
;;

(defun vla-get (proplist)
(if (and proplist (atom proplist))
(vlax-get-property
(vlax-get-acad-object)
proplist
)
(vla-get-aux (vlax-get-acad-object) proplist)
)
)

(defun vla-get-aux (obj proplist / value result)
(cond
( (not proplist) obj)
(t (setq value
(if (member (type (car proplist)) '(int str))
(vlax-invoke-method obj 'Item (car proplist))
(vlax-get-property obj (car proplist))
)
)
(setq result (vla-get-aux value (cdr proplist)))
(if (and (cdr proplist)
(eq (type value) 'vla-object)
)
(vlax-release-object value)
)
result
)
)
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

It's too much typing for me to fully explain what the
above functions do, but this should make it perfectly
clear:

Command: (vla-get '(ActiveDocument ActiveLayer Name))
"0"

Command: (vla-get '(ActiveDocument Layouts 1 Name))
"Layout2"

[You need at least 1 object in Modelspace for this]:

Command: (vla-get '(ActiveDocument Modelspace 0 EntityName))
"AcDbCircle"

Command: (vla-get '(ActiveDocument ActiveLayout))
#<VLA-OBJECT IAcadLayout 01bc0924>

The really interesting part, is that all intermediate
results which are VLA-OBJECTS are also released via
calls to (vlax-release-object)

Way nice, Tony - Thanks!

Best regards,
David Kozina
 
John,

Many thanks for the 'heads up' regarding GetBoundingBox. I know I've used that a time or two - and I thought it was working okay after switching over to vlax-invoke, but, on second thought, maybe not... I'll have to go back and recheck that now.

What other vla- <-> vlax- idiosyncrasies have you encountered?

Best regards,
David Kozina

John Uhden said:
I've found that (vlax-invoke), (vlax-get), and (vlax-put) work the best most of the time and avoid the tedium of dealing with safearrays and variants. BUT, you can't use them all the time. A prime example is the GetBoundingBox method where you have to supply the quoted symbol names for the return values of MinPoint and MaxPoint.

(vlax-invoke Object 'GetBoundingBox 'MinPoint 'Maxpoint) doesn't set the symbols MinPoint or MaxPoint, whereas (vla-GetBoundingBox Object 'MinPoint 'Maxpoint) will.
....
 
John,

Could you provide a specific example wherein
(vlax-invoke-method obj 'GetBoundingBox 'Min_pt 'Max_pt)
does not work as advertised?

After doing some extremely minimal (and most likely far-from-sufficient) testing, I'm not coming across any noticeable difficulties.

Or is this more like one of those "Twilight Zone-ish" inconsistent gremlin thingies that sometimes happens and sometimes doesn't?
 
(vlax-invoke-method 'GetBoundingBox 'minpt 'maxpt) always works. I believe he was referring to this not working with (vlax-invoke), but that's because (vlax-invoke) handles the results of multiple output parameters internally, and always returns them as a list of results (and converts to LISP types where appropriate).

While that may seem easy, it requires a lot of additional code in the internal implementation, whereas because the use of quoted symbols is consistent and doesn't attempt to do any conversion to LISP types, it requires little additional code internally.
 
i use something similar of the function used in the a-mtext.lsp under the sample\visual lisp\reactors folder is call it: update-parameter

i did the update to use vlax-put-property and also vlax-property-available-p

and both functions works just fine... hth

David Kozina
 
(vlax-invoke-method 'GetBoundingBox 'minpt 'maxpt) always works. I believe he was referring to this not working with (vlax-invoke), but that's because (vlax-invoke) handles the results of multiple output parameters internally, and always returns them as a list of results (and converts to LISP types where appropriate).

While that may seem easy, it requires a lot of additional code in the internal implementation, whereas because the use of quoted symbols is consistent and doesn't attempt to do any conversion to LISP types, it requires little additional code internally.
 
Tony (and Jason),

Again, thanks for the additional info on these functions. I see that vlax-invoke doesn't do the same thing.

Just was wondering if John had come across something else that I ought to be aware of.

I think that's been a major part of the 'learning curve' difficulty for me with these "new" functions - there's even more ways now to 'skin the cat', and up 'til recently, I just haven't seen too much in the way of direction for what is the more optimal path to take. But I think I'm starting to see at least some progress in getting these functions to at least *work*, so I'm happy about that.

On another front, I know I'm still very much in the dark regarding the proper way to handle errors - so I think I've gone way overboard in some of my routines to try and not allow anything 'wrong' to occur. I'll probably post some (more) god-awful code one of these days, hoping to get some 'optimization' guidelines on how it could be done better. I'm sure I'll be able to provoke *somebody* out there... ;)

And no doubt learn much more at the same time...
 
Tony:

(vlax-invoke) doesn't work with quoted return symbols at all, internally, externally, whatever. That's all I meant.

But I sorta think that...
(defun lwpoly#1 (Coords)
(vla-AddLightWeightPolyline
Model
(vlax-safearray-fill
(vlax-make-safearray vlax-vbDouble (cons 0 (1- (length Coords)))) Coords ) )
)

and...
(defun lwpoly#2 (Coords)
(vlax-invoke-method
Model
'AddLightWeightPolyline
(vlax-safearray-fill
(vlax-make-safearray vlax-vbDouble (cons 0 (1- (length Coords)))) Coords ) )
)

both look like a bundle more code than...
(defun lwpoly#3 (Coords)
(vlax-invoke Model 'AddLightWeightPolyline Coords)
)

the last of which also happens to be twice as fast.
 

Latest threads

Back
Top