Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

[REBOL] Re: Reflectivity: How a function can know its own name ?

From: joel:neely:fedex at: 28-Mar-2002 8:14

Hi, Laplace, I guess I don't understand the problem you're trying to solve. laplace wrote:
> ... I want to do something like this ...: > > generic_function: make function ['function_name] > [ > print function_name > ] > > func1: make function! [ > instruction11 instruction12 > generic_function [name of self] > instruction13 > ] > func2: make function! [ > generic_function [name of self] > instruction21 > ] > ... > func10: make function! [ > instruction31 > generic_function [name of self] > ] >
First of all, let's remember that to REBOL the expression someword: func [] [print "Hi, Mom!"] first creates a FUNCTION! value, and then simply sets the (arbitrarily-named) word SOMEWORD to refer to that FUNCTION! value. It's a one-way arrow. It is just as meaningless to talk about "the name of a function" as it is to talk about "the color of a string" or "the mother of an integer". In the example you offer, GENERIC_FUNCTION is simply printing whatever value you supply as its argument. That being the case, you can pass it a string which contains a human-readable message, without worrying about which word was used to access the calling function. For example:
>> generic_function: func [s [string!]] [print s] >> func1: func [] [
[ ;do other stuff [ generic_function "Larry" [ ;do more other stuff [ ]
>> func2: func [] [
[ ;do other stuff [ generic_function "Curly" [ ;do more other stuff [ ]
>> func3: func [] [
[ ;do other stuff [ generic_function "Moe" [ ;do more other stuff [ ] Now you can get the behavior that you seem to want...
>> func1
Larry
>> func2
Curly
>> func3
Moe ... where invoking any of those functions causes the "generic" action to print a message. However, this approach lets you know *WHICH*FUNCTION* was invoked, regardess of how we got to that function value, as follows:
>> first-function: :func1 >> second-function: :func2 >> third-function: :func3
Now there are three additional words that refer to *THE*SAME* function values that we created earlier, but accessing them through these new references doesn't change the identity of each function.
>> first-function
Larry
>> second-function
Curly
>> third-function
Moe We can also create and use references to the functions without the need for words that refer to them individually.
>> block-o-funcs: reduce [:func1 :func2 :func3]
== [func [][ generic_function "Larry" ] func [][ generic_function "Curly" ] func [][ generic_functi... Now the same function values are in a block, which we can traverse to use the functions inside it.
>> foreach funcref block-o-funcs [funcref]
Larry Curly Moe We can store references to functions in other arbitrarily complicated structures:
>> look-up-table: []
== []
>> foo: tail block-o-funcs
== []
>> for char #"C" #"A" -1 [
[ foo: back foo [ append look-up-table reduce [char first foo] [ ] == [#"C" func [][ generic_function "Moe" ] #"B" func [][ generic_function "Curly" ] #"A" func [][ g... ... and then retrieve and evaluate the *SAME* functions.
>> for letter #"A" #"C" 1 [do select look-up-table letter]
Larry Curly Moe When we say "functions are first-class values in REBOL" we mean that they can be stored, retrieved, created, passed as arguments to functions, returned as values from functions,... in short, can be used as any other data type. This is A Good Thing, not a limitation, but it does require us to think about them a little differently than we do for more limited languages.
> If I don't have a "name of self" for function, each time I > add a new function to call generic function, it is in the > code of generic function that I would have to test the name > of the function with a more or less gigantic number of test > instructions: > > generic_function: make function ['function_name] > [ > if function_name = "func1" > [ > instruction11 > instruction12 > print function_name > instruction13 > ] > > if function_name = "func2" > [ > print function_name > instruction21 > ] > > ] >
This appears to be different from your original description, in that you're now embedding the behavior of what were the different functions into a single "master function" and letting its argument control which sub-expressions to evaluate. There are lots of ways to do something like this second example, as others have pointed out. You could also use refinements... generic_function: func [/type1 /type2 /type2 ...] [ if type1 [...] if type2 [...] if type3 [...] ... ] But this appears to be a step backwards. The Right Thing To Do is factor out the common, parameterizable behavior into its own identity, then use it with appropriate parameter(s) as needed. Hope this helps! -jn- -- ; Joel Neely joeldotneelyatfedexdotcom REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] { | e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]