Firstly, GetAttributes is a method applicable to a VLA Block Reference. To implement a method on a VLA-Object we could go down one of three routes:
1) vla-[method]
Structure:
(vla-[color=green][method][/color] [color=red]<Object>[/color] [color=blue][Param1] [Param2] ... [ParamN][/color])
e.g.
(vla-[color=green]GetAttributes[/color] [color=red]<VLA-BlockReference>[/color])
Where 'Object' is the VLA-Object to which the method appies, and 'Param1,...,ParamN' are parameters which may be required by the method which bear some consequence on the outcome of the method.
This implementation of the method returns data in the form of a Variant, whose contents (perhaps a [Safe]Array) would need to be extracted (using vlax-variant-value), and this [Safe]Array would then need to be converted to a List (using vlax-safearray->list).
2) vlax-invoke-method
Structure:
(vlax-invoke-method [color=red]<Object>[/color] [color=green]<Method>[/color] [color=blue][Param1] [Param2] ... [ParamN][/color])
e.g.
(vlax-invoke-method [color=red]<VLA-BlockReference>[/color] [color=green]'GetAttributes[/color])
Similar to the above route, however the method is supplied as an argument to the function vlax-invoke-method (in the first example the method has its own function).
This route will also return any data in the form of a variant and a similar procedure would need to be followed to convert it to a native LISP data type (such as a List).
3) vlax-invoke
Structure:
(vlax-invoke [color=red]<Object>[/color] [color=green]<Method>[/color] [color=blue][Param1] [Param2] ... [ParamN][/color])
e.g.
(vlax-invoke [color=red]<VLA-BlockReference>[/color] [color=green]'GetAttributes[/color])
This is an undocumented function, and has a structure similar to the previous example. The difference is that this method will return any data in a native LISP data type (a List), instead of a Variant, so no conversion is required.
Back to my code, where I have used:
(vlax-invoke [color=red]block [/color]'[color=green]GetAttributes[/color])
'block' is the VLA Block Reference, and GetAttributes is the method to be implemented on such object. GetAttributes is expressed as a quoted symbol, but this could also be expressed as a string (similar to how the setvar/getvar functions can be used).
And so, should the block have attributes, the above will return a list of the attribute objects, something like:
(<VLA Attribute1> <VLA Attribute2> ... <VLA AttributeN>)
Now, many seem to find mapcar difficult to understand, but persevere, since it is a very useful function.
mapcar will take a function argument and a number of list arguments. The number of lists must equal the number of arguments required by the supplied function.
When evaluated, mapcar will evaluate the function on every item of the supplied list(s), and return a list of the result of each evaluation. mapcar will stop evaluation as soon as a list is exhausted.
Note that the function can be any function, taking any number of arguments. lambda describes an anonymous function (usually used for a one-off usage, hence not warranting the overhead of a 'defun'), and, as a function, can be supplied as an argument to mapcar.
A few examples:
;; Add 1 to every element of a list:
([color=blue]mapcar [/color]'[color=red]1+[/color] '[color=green](1 2 3 4 5)[/color])
==> '(2 3 4 5 6)
(defun [color=red]AddTwo [/color]( x ) (+ x 2))
([color=blue]mapcar [/color]'[color=red]AddTwo [/color]'[color=green](1 2 3 4 5)[/color])
==> (3 4 5 6 7)
([color=blue]mapcar [/color]'[color=red](lambda ( x ) (+ x 2))[/color] [color=green]'(1 2 3 4 5)[/color])
==> (3 4 5 6 7)
([color=blue]mapcar [/color]'[color=red]+[/color] '[color=green](1 2 3 4 5) '(3 4 5 6 7)[/color])
==> (4 6 8 10 12) = ((+ 1 3) (+ 2 4) (+ 3 5) (+ 4 6) (+ 5 7))
(defun [color=red]foo [/color]( string number ) (strcat string (itoa number)))
([color=blue]mapcar [/color]'[color=red]foo [/color][color=green]'("a" "b" "c") '(1 2 3)[/color])
("a1" "b2" "c3")
([color=blue]mapcar [/color]'[color=red](lambda ( string number ) (strcat string (itoa number)))[/color] '[color=green]("a" "b" "c") '(1 2 3)[/color])
("a1" "b2" "c3")
Similarly a lambda function can be used with the apply function:
(defun [color=red]averageof2 [/color]( num1 num2 ) (/ (+ num1 num2) 2.))
([color=blue]apply [/color]'[color=red]averageof2 [/color]'[color=green]( 1 2 )[/color])
==> 1.5
([color=blue]apply[/color][color=red] '(lambda ( num1 num2 ) (/ (+ num1 num2) 2.))[/color] '[color=green]( 1 2 )[/color])
==> 1.5
Or a general average function:
(defun [color=blue]average [/color]( lst ) (/ ([color=blue]apply [/color]'[color=red]+[/color] lst) (float (length lst))))
(average '( 1 2 3 4 ))
==> 2.5
Back to my code:
I use a lambda function taking a single argument (a VLA attribute object), returning a dotted pair of the TagString and TextString properties for the VLA Attribute Object.
I could equally have defined a separate function:
(defun [color=red]_TagText[/color] ( attrib )
(cons (vla-get-TagString attrib ) (vla-get-TextString attrib))
)
([color=blue]mapcar [/color]'[color=red]_TagText[/color] [color=green](vlax-invoke block 'GetAttributes)[/color])
However, since I'm only using the function for this expression, it seems a little overkill to define a whole function for it. Also, using the lambda function improves the readability of the code since the intention of the function is expressed in the same statement and not elsewhere in the code.
As an overview, think about the code in this way:
([color=blue]mapcar[/color]
[color=red] (function
(lambda ( attrib )
(cons (vla-get-TagString attrib ) (vla-get-TextString attrib))
)
)[/color]
[color=green] (<VLA-Attribute1> <VLA-Attribute2> ... <VLA-AttributeN>)[/color]
)
(
(cons (vla-get-TagString <VLA-Attribute1>) (vla-get-TextString <VLA-Attribute1>))
(cons (vla-get-TagString <VLA-Attribute2>) (vla-get-TextString <VLA-Attribute2>))
...
(cons (vla-get-TagString <VLA-AttributeN>) (vla-get-TextString <VLA-AttributeN>))
)
Returning:
(
(<Tag1> . <Text1>)
(<Tag2> . <Text2>)
...
(<TagN> . <TextN>)
)
A quick note on the use of the function function: this just declares the argument as a function. The use of the apostrophe to indicate that the supplied functional argument is not to be evaluated (but instead taken as an argument for mapcar/apply etc), has the same result as using the function function - with perhaps a small performance improvement by using the function function since the interpreter doesn't have to 'make sense' of the quoted expression.
If you still have questions about my explanation, please ask. But I would ask that you spend some time analyzing my examples to understand each one in turn before asking questions.
Also, I would suggest that you read about passing arguments to functions, and similarly writing functions taking a number of arguments.
Hope this helps!
Lee