pass a function to a function

pass a function to a function

Anonymous
Not applicable
1,429 Views
20 Replies
Message 1 of 21

pass a function to a function

Anonymous
Not applicable
I have some lines of code that will iterate through all layouts in a drawing. I would like to make it into a function. I want to pass it to another function as a parameter so that function will run on each layout as it iterates through. Can you pass a function to another function? Can you pass a function with parameters of its own?

Here's the code. Thanks for help...

(setq IAcadDocument (vla-get-ActiveDocument (vlax-get-Acad-Object))
IAcadLayouts (vla-get-Layouts IAcadDocument)
IActiveLayout (vla-get-ActiveLayout IAcadDocument)
) ;_ setq
(vlax-for IAcadLayout IAcadLayouts
(if (not (wcmatch (vla-get-name IAcadLayout) "Model"))
(progn
(print (vla-get-Name IAcadLayout))
(vla-put-ActiveLayout IAcadDocument IAcadLayout)
;;;place function to be ran on each layout here;;
(MyFunc)

;(print (append (getvar "LIMMIN") (getvar "LIMMAX")))
)
)
) ;_ vlax-for
(vla-put-ActiveLayout IAcadDocument IActiveLayout)
;(textscr)
(princ)
0 Likes
1,430 Views
20 Replies
Replies (20)
Message 2 of 21

Anonymous
Not applicable
I don't have the specifics, but I would think you could pass the function
name as a string, then using the READ (maybe not that one) function actually
call it.

I'm not the best person to respond, but thought I'd throw an idea at you. I
seem to remember doing something similar, but that was waaaay too long ago
for me to remember specifics.

wrote in message news:5248241@discussion.autodesk.com...
I have some lines of code that will iterate through all layouts in a
drawing. I would like to make it into a function. I want to pass it to
another function as a parameter so that function will run on each layout as
it iterates through. Can you pass a function to another function? Can you
pass a function with parameters of its own?

Here's the code. Thanks for help...

(setq IAcadDocument (vla-get-ActiveDocument (vlax-get-Acad-Object))
IAcadLayouts (vla-get-Layouts IAcadDocument)
IActiveLayout (vla-get-ActiveLayout IAcadDocument)
) ;_ setq
(vlax-for IAcadLayout IAcadLayouts
(if (not (wcmatch (vla-get-name IAcadLayout) "Model"))
(progn
(print (vla-get-Name IAcadLayout))
(vla-put-ActiveLayout IAcadDocument IAcadLayout)
;;;place function to be ran on each layout here;;
(MyFunc)

;(print (append (getvar "LIMMIN") (getvar "LIMMAX")))
)
)
) ;_ vlax-for
(vla-put-ActiveLayout IAcadDocument IActiveLayout)
;(textscr)
(princ)
0 Likes
Message 3 of 21

Anonymous
Not applicable
In second function.. just call the function you want.
e..g.

(defun 2nd_fun ()
(do_first_fun)
)
0 Likes
Message 4 of 21

Anonymous
Not applicable
Or, pass it a number..
e.g.
(defun 2nd_fun (fun_num)
(if (= fun_num 1)(do_first_fun))
(if (= fun_num 2)(do_next_fun))
)

Bob
0 Likes
Message 5 of 21

Anonymous
Not applicable
Thanks for the quick responses. I forgot you can pass a regular function to another function with no problem. It's where I pass another function with parameters of its own that I have trouble. Like, say I have these two functions...

(defun Func1 ()
(command "text" "4,4" "0.2" "0" "hello")
)

(defun Func2 (text inspnt hght)
(command "text" inspnt hght "0" text)
)

Now, I can pass Func1 to my LayoutIterate function.

(LayoutIterate Func1)

But I can't pass Func2 because it has parameters

(LayoutIterate (Func2 "hello" "4,4" "0.5"))

Not sure how to go about this. Like Tom D said, it might work with something like READ or EVAL. Or maybe my whole approach is wrong.
0 Likes
Message 6 of 21

Anonymous
Not applicable
try:
(setq lst '("hello" "4,4" "0.5"))
(funt_1 lst)
(funt_2 lst)
0 Likes
Message 7 of 21

Anonymous
Not applicable
Jason Roper wrote:
> Thanks for the quick responses. I forgot you can pass a regular function to another function with no problem. It's where I pass another function with parameters of its own that I have trouble. Like, say I have these two functions...
>
> (defun Func1 ()
> (command "text" "4,4" "0.2" "0" "hello")
> )
>
> (defun Func2 (text inspnt hght)
> (command "text" inspnt hght "0" text)
> )
>
> Now, I can pass Func1 to my LayoutIterate function.
>
> (LayoutIterate Func1)
>
> But I can't pass Func2 because it has parameters
>
> (LayoutIterate (Func2 "hello" "4,4" "0.5"))
>
> Not sure how to go about this. Like Tom D said, it might work with something like READ or EVAL. Or maybe my whole approach is wrong.

(LayoutIterate (function (lambda () (Func2 "hello" "4,4" "0.5"))))

- in interpreted code this would work as well with '(lambda ...) instead
of (function (lambda ...)), but the latter produces better code when
compiled.

Also, if you know the parameters inside your LayoutIterate function (not
sensible in a general tool) you could work with APPLY.

--
0 Likes
Message 8 of 21

Anonymous
Not applicable
Hi,

You don't pass it as a parameter, but you call it within the body of your
main function. The next code works flawlesly and it's only normal, because
this is what AutoLISP is all about, passing functions to functions, with or
without arguments (parameters).

(defun Func1 ()
(command "text" "4,4" "0.2" "0" "hello")
)
(defun Func2 (text inspnt hght)
(command "text" inspnt hght "0" text)
)
(defun FunctionIterate ()
(command "text" "4,5" "0.2" "0" "This is FunctionIterate")
(func1)
(func2 "Func2" "4,3" "0.2")
(princ)
)

You can see the result in the attached screen shot.

Regards,

Constantin


a écrit dans le message de news:
5248241@discussion.autodesk.com...
I have some lines of code that will iterate through all layouts in a
drawing. I would like to make it into a function. I want to pass it to
another function as a parameter so that function will run on each layout as
it iterates through. Can you pass a function to another function? Can you
pass a function with parameters of its own?

Here's the code. Thanks for help...

(setq IAcadDocument (vla-get-ActiveDocument (vlax-get-Acad-Object))
IAcadLayouts (vla-get-Layouts IAcadDocument)
IActiveLayout (vla-get-ActiveLayout IAcadDocument)
) ;_ setq
(vlax-for IAcadLayout IAcadLayouts
(if (not (wcmatch (vla-get-name IAcadLayout) "Model"))
(progn
(print (vla-get-Name IAcadLayout))
(vla-put-ActiveLayout IAcadDocument IAcadLayout)
;;;place function to be ran on each layout here;;
(MyFunc)

;(print (append (getvar "LIMMIN") (getvar "LIMMAX")))
)
)
) ;_ vlax-for
(vla-put-ActiveLayout IAcadDocument IActiveLayout)
;(textscr)
(princ)
0 Likes
Message 9 of 21

Anonymous
Not applicable
Oops,

This should be here:

"... The next code works flawlesly 🙂 and it's only normal, because this is
what AutoLISP is all about, passing functions to functions, with or without
arguments (parameters)...:

(alert (strcat "A" "B" "C"))

Constantin

a écrit dans le message de news:
5248241@discussion.autodesk.com...
I have some lines of code that will iterate through all layouts in a
drawing. I would like to make it into a function. I want to pass it to
another function as a parameter so that function will run on each layout as
it iterates through. Can you pass a function to another function? Can you
pass a function with parameters of its own?

Here's the code. Thanks for help...

(setq IAcadDocument (vla-get-ActiveDocument (vlax-get-Acad-Object))
IAcadLayouts (vla-get-Layouts IAcadDocument)
IActiveLayout (vla-get-ActiveLayout IAcadDocument)
) ;_ setq
(vlax-for IAcadLayout IAcadLayouts
(if (not (wcmatch (vla-get-name IAcadLayout) "Model"))
(progn
(print (vla-get-Name IAcadLayout))
(vla-put-ActiveLayout IAcadDocument IAcadLayout)
;;;place function to be ran on each layout here;;
(MyFunc)

;(print (append (getvar "LIMMIN") (getvar "LIMMAX")))
)
)
) ;_ vlax-for
(vla-put-ActiveLayout IAcadDocument IActiveLayout)
;(textscr)
(princ)
0 Likes
Message 10 of 21

Anonymous
Not applicable
I think you are right Constantin,
I guess what I was trying to do is make everything too "modular". My thinking was if I had some routine already developed, I could plug it into the LayoutIterate loop. But, it would seem the code is more suited to a main body function. Not to hard to modify.
0 Likes
Message 11 of 21

Anonymous
Not applicable
As a friend of mine uses to say, "sometimes, because of the trees, we can't
see the forest 🙂 But as I said in my last post, you should be able to pass
a function to another function too, this is the structure of AutoLISP. The
most inner function executes and the result is passed to the next one, and
so on, and so on. The call (strcat "A" "B" "C") produces as returning result
the string "ABC", which is passed as parameter for (alert string) function.
Therefore if (alert (strcat "A" "B" "C")) works, everything respecting the
structure, the rules and the syntax should work too, no matter whose
functions are and how are they named.

Regards,

Constantin

a écrit dans le message de news:
5249065@discussion.autodesk.com...
I think you are right Constantin,
I guess what I was trying to do is make everything too "modular". My
thinking was if I had some routine already developed, I could plug it into
the LayoutIterate loop. But, it would seem the code is more suited to a
main body function. Not to hard to modify.
0 Likes
Message 12 of 21

uncoolperson
Enthusiast
Enthusiast
_$ (defun subfun (somethin) (alert somethin))
SUBFUN
_$ (defun bigfun( smallfun msg) (smallfun msg))
BIGFUN
_$ (bigfun subfun "look where i'm at")

_$ (defun bigfun2 (mess) (eval mess))
BIGFUN2
_$ (bigfun2 '(subfun "look where i went"))

_$ (defun bigfun3 (thing1 thing2) (if (listp thing1) (eval thing1) (thing1 thing2)))
BIGFUN3
_$ (bigfun3 subfun "look where I'm at")
nil
_$ (bigfun3 '(subfun "look where i went") nil)


okay, one more cause thing is getting fun

(defun bigfun4 (thing1 thing2) (IF (LISTP thing1)(EVAL (subst (strcat (cadr thing1) thing2) (cadr thing1) thing1) )(thing1 thing2)))
(bigfun4 subfun "see where this is going?")
(bigfun4 '(subfun "following ") "okay?")

Message was edited by: uncoolperson Message was edited by: uncoolperson
0 Likes
Message 13 of 21

Anonymous
Not applicable
>getting fun

A little cryptic for my taste. I don't know if the OP is gonna catch your drift. But it is possible to "build" a function call from variables, as you imply. For instance the call to (Func2 "hello" "4,4" "0.5") could take the form:

(eval (list 'Func2 string1 string2 string3))
0 Likes
Message 14 of 21

Anonymous
Not applicable
Hi Tom,

I had kind of the same feeling. I think that just for the sake of the
elegance and beauty of the solutions is worth it, but most of the time it's
really necessary to assign data to variables and to pass values between
functions in a concise, clear and simple manner.

Constantin



a écrit dans le message de news:
5249395@discussion.autodesk.com...
>getting fun

A little cryptic for my taste. I don't know if the OP is gonna catch your
drift. But it is possible to "build" a function call from variables, as you
imply. For instance the call to (Func2 "hello" "4,4" "0.5") could take the
form:

(eval (list 'Func2 string1 string2 string3))
0 Likes
Message 15 of 21

Anonymous
Not applicable
This is not exactly what you asked for but it is an example of a function
that will
define another function on the fly to reload a lisp file given the string to
name the
function and the path and filename to load.

(defun LOAD_CMD (NAM FIL / PRG$ S ST)
(setq ST (strcat "(()(load " (chr 34) FIL (chr 34) "))")) ;func as a
string
(setq S (read ST)) ;strip
quotes
(setq PRG$ (strcase (strcat "C:" NAM))) ;cmd name for
module
(set (read PRG$) S) ;define function as a
variable
(or (eval (read PRG$))) ;T if new command fuction is
defined
)

Call this to make a new command

(load_cmd "SUBR" "c:\\programs\\subr.lsp")

then at the command line
Command: SUBR
LAST-DEFUN-NAMED-IN-FILE








wrote in message news:5248241@discussion.autodesk.com...
I have some lines of code that will iterate through all layouts in a
drawing. I would like to make it into a function. I want to pass it to
another function as a parameter so that function will run on each layout as
it iterates through. Can you pass a function to another function? Can you
pass a function with parameters of its own?

Here's the code. Thanks for help...

(setq IAcadDocument (vla-get-ActiveDocument (vlax-get-Acad-Object))
IAcadLayouts (vla-get-Layouts IAcadDocument)
IActiveLayout (vla-get-ActiveLayout IAcadDocument)
) ;_ setq
(vlax-for IAcadLayout IAcadLayouts
(if (not (wcmatch (vla-get-name IAcadLayout) "Model"))
(progn
(print (vla-get-Name IAcadLayout))
(vla-put-ActiveLayout IAcadDocument IAcadLayout)
;;;place function to be ran on each layout here;;
(MyFunc)

;(print (append (getvar "LIMMIN") (getvar "LIMMAX")))
)
)
) ;_ vlax-for
(vla-put-ActiveLayout IAcadDocument IActiveLayout)
;(textscr)
(princ)
0 Likes
Message 16 of 21

Anonymous
Not applicable
Thanks for all the great responses everyone. Just wanted to let you know that I'm still following this interesting post. I'll need some time to play with these ideas.
0 Likes
Message 17 of 21

Anonymous
Not applicable
Aha!

First pass function with variables as a list...

(LayoutIterate (list 'Func2 "hello" "4,4" "0.5"))

...and then in LayoutIterate

(defun LayoutIterate (PassFunc)
...
...

(eval PassFunc);evaluate list
...
)


Brillant! Just what I was looking for.

Thanks WB, CG, TS, uncool, chubby, TD.
All of your input helped a lot.
0 Likes
Message 18 of 21

Anonymous
Not applicable
Jason Roper wrote:
> Aha!
>
> First pass function with variables as a list...
>
> (LayoutIterate (list 'Func2 "hello" "4,4" "0.5"))
>
> ...and then in LayoutIterate
>
> (defun LayoutIterate (PassFunc)
> ...
> ...
>
> (eval PassFunc);evaluate list
> ...
> )

That is a slightly brute-force method of solving this, but works as long
as your parameters are constants or global variables. If you use
variables that have different values inside your function and outside,
you might have different results than you expected.


_$ (setq a 'outer-a b 'outer-b)


_$ (defun test1 (func / a b)
(setq a 'inner-a b 'inner-b)
(eval func))

_$ (test1 (list 'cons a b))
(nil)
_$ (test1 (list 'cons 'a 'b))
(INNER-A . INNER-B)

_$ (defun test2 (func / a b)
(setq a 'inner-a b 'inner-b)
(apply (car func) (cdr func)))

_$ (test2 (list 'cons a b))
(OUTER-A . OUTER-B)
_$ (test2 (list 'cons 'a 'b))
(A . B)
_$ (test2 (function(lambda()(cons a b))))
(quote #)

_$ (defun test3 (func / a b)
(setq a 'inner-a b 'inner-b)
(apply func nil))

_$ (test3 (function(lambda()(cons a b))))
(INNER-A . INNER-B)

This test3 was rather surprising, as I expected the outer values
(as I would get in Common Lisp).

--
0 Likes
Message 19 of 21

Anonymous
Not applicable
Hi Jason,

Is there something that I miss or what ? I can not understand
what are you up to ! Why would do you want to scratch your
left ear with your right hand behind your head ? The next
AutoLISP statement,

(defun Func2 (text inspnt hght)
[1]
(command "text" inspnt hght "0" text)
)

is already a list, although defun [DEfine FUNction] makes it
a special one. So why do you want to pass a list as a list, but
with "don't eval" quote as in:

(list 'Func2 "hello" "4,4" "0.5")
[2]

and then try to evaluate it later ? Why first "don't eval" and then
"eval" later, when in fact

(LayoutIterate (list 'Func2 "hello" "4,4" "0.5")) [3]

would do exactly the same thing as

(defun LayoutIterate ()
[4]
(Func2 "hello" "4,4" "0.5")
)

and then call it

(LayoutIterate)
[5]

or

(defun LayoutIterate (text inspnt hght) [6]
(Func2 (text inspnt hght))
)

and then call it

(LayoutIterate "hello" "4,4" "0.5") [7]

Why do you need to pass the function as an argument ?

Constantin



a écrit dans le message de news:
5252241@discussion.autodesk.com...
Aha!

First pass function with variables as a list...

(LayoutIterate (list 'Func2 "hello" "4,4" "0.5"))

...and then in LayoutIterate

(defun LayoutIterate (PassFunc)
...
...

(eval PassFunc);evaluate list
...
)


Brillant! Just what I was looking for.

Thanks WB, CG, TS, uncool, chubby, TD.
All of your input helped a lot.
0 Likes
Message 20 of 21

Anonymous
Not applicable
I think that that the wrapping make it hard to understand so
I post it again:


"Is there something that I miss or what ? I can not understand
what are you up to ! Why would do you want to scratch your
left ear with your right hand behind your head ? The next
AutoLISP statement,

(defun Func2 (text inspnt hght) [1]
(command "text" inspnt hght "0" text)
)

is already a list, although defun [DEfine FUNction] makes it
a special one. So why do you want to pass a list as a list, but
with "don't eval" quote as in:

(list 'Func2 "hello" "4,4" "0.5") [2]

and then try to evaluate it later ? Why first "don't eval" and
then "eval" later, when in fact

(LayoutIterate (list 'Func2 "hello" "4,4" "0.5")) [3]

would do exactly the same thing as

(defun LayoutIterate () [4]
(Func2 "hello" "4,4" "0.5")
)

and then call it

(LayoutIterate) [5]

or

(defun LayoutIterate (text inspnt hght) [6]
(Func2 (text inspnt hght))
)

and then call it

(LayoutIterate "hello" "4,4" "0.5") [7]

Why do you need to pass the function as an argument ?"

Constantin








a écrit dans le message de news:
5252241@discussion.autodesk.com...
Aha!

First pass function with variables as a list...

(LayoutIterate (list 'Func2 "hello" "4,4" "0.5"))

...and then in LayoutIterate

(defun LayoutIterate (PassFunc)
...
...

(eval PassFunc);evaluate list
...
)


Brillant! Just what I was looking for.

Thanks WB, CG, TS, uncool, chubby, TD.
All of your input helped a lot.
0 Likes