ACTION! Mold Shows Cached Name (If Available)

Since the label used to reference the function may be cached in the cell, I'm making MOLD give that if it's there, plus the parameter list:

>> mold reduce [1 2 :help]
== "[1 2 #[action! {help} ['topic /doc]]]"

It's useful, and it also will help make any bugs or oversights in the feature more obvious--if you see things with labels that seem wrong, please report it (but make sure you've read this whole post first...)

Remember: It's The Name Last Accessed Through

Function value cells that were produced and never given a name won't have a label, so it just omits it:

>> mold reduce [1 2 func [x] [print [x]]]
== "[1 2 #[action! [x]]]"

Remember this isn't the name that the function was defined with (SET-WORD!s do not manipulate the cache). It's the name the action was last accessed through:

>> foo: :help
== "[1 2 #[action! {help} ['topic /doc]]]"  ; here, accessed through :help

>> mold reduce [1 2 :foo]
== "[1 2 #[action! {foo} ['topic /doc]]]"  ; but here, accessed through :foo

We might review the question of if SET-WORD!s update the cache. I'm open to it, but there are some complications various places if we do that.

Don't Forget to Be Impressed: The Feature is Robust!

>> f: make frame! :append

>> f/value: 10

>> reeval make action! f [a b c]
== [a b c 10]

>> reeval make action! f 12-Dec-20120
** Script Error: append does not allow #[datatype! date!] for its series argument
                 ; ^-- neat!

>> make action! f
== #[action! {append} [series /part /only /dup /line]]
             ; ^-- now you can keep tabs on what the magic is doing...

Originally I left the label feature out of the 2020 accomplishments list, but that was an oversight. It's going to matter to help legibility of debug stacks, when you are creating and using these things in mid-expression...it would suck if such power tools showed no name information.

Be Aware: Of Function Derivation Issues...

This could mean that temporary names that aren't meaningful get exposed, e.g. when writing something that makes derivative functions:

>> greetify: func [action] [adapt :action [print "HELLO THERE!"]]
== #[action! [action]]  ; no cached-name, generated with func [...]

>> friendly-append: greetify :append
== #[action! {action} [series value /part /only /dup /line]]
             ; ^-- note this is {action} from `:action`, not {append} 

>> friendly-append [a b c] <d>
HELLO THERE!
[a b c <d>]

>> mold reduce [1 2 greetify :help]
== "[1 2 #[action! {action} ['topic /doc]]]"

You can see how the parameter name action contaminates to lose the label that a function derivation process started out with. You can use GET to subert this, which doesn't update the label the way accessing through a GET-WORD! does.

>> greetify: func [action] [adapt get 'action [print "HELLO THERE!"]]
== #[action! [action]]  ; no cached-name from a last fetch

>> friendly-append: greetify :append
== #[action! {append} [series value /part /only /dup /line]]
             ; ^-- see this is now {append} and not {action}

This method is used by ADAPT and SPECIALIZE and all those functions. However, it's not perfect because it's a modified version. The label cache is really only a hint.

Why Not Include the Body of the Action

Historical "molding" of an action tried to give its source code. I deemed this as not a useful direction, since the source code lacks bindings you can't get the action back from it. All it does is make blocks that contain actions nigh-illegible.

Red continues this pattern, and doesn't use construction syntax...hence making the representation look like it contains the WORD! func, which is even worse:

red>> append [1 2] :help-string
== [1 2 func [{Returns information about functions, values, objects, and datatypes.} 
    'word [any-type!] 
    /local ref-given? value
][
    clear output-buffer 
    case [
 ...

I don't have any perfect answers here. What you really need is some identity to get at the function. The pointer value is about the best we'd have, though pointers are unstable and you might look them up after a mold and they could be invalid (or point to something different entirely).

For the near term, I think this compact rendering that includes a label is best, and making getting at the function's body done with other tools.

3 Likes

Let's Look At An Example...

call-with-10: func [your-func [action!]] [
    apply :your-func [10]
]

print-tag: func [value [tag!]] [
    print mold value
]

>> call-with-10 :print-tag
** Error: [[???]] does not accept INTEGER! for its value argument 

So here you'd get an error because you're passing an integer where a tag was expected. What name do you expect in the error: PRINT-TAG or YOUR-FUNC?

I think PRINT-TAG is probably the more useful option in this kind of scenario. This suggests a default of making SET-WORD! cache the name, while GET-WORD! does nothing.

Note: Originally GET-WORD!'s captured the name because it was a direct translation of the old method of taking a WORD! to APPLY as a way of asking APPLY to preserve the name of the function tied to that word. But now I think it's probably better to cache the name on the SET-WORD!.

What About When You Don't Want To Cache the Name?

How about this slightly different example:

call-with-10: func [your-func [action!]] [
    your-func-hi: adapt :your-func [print "hi"]
    apply :your-func-hi [10]
]

print-tag: func [value [tag!]] [
    print mold value
]

call-with-10 :print-tag

This gets more complicated, when you have a mutation to a function...it's no longer the same thing.

But some cases are capturing functions into variables with the idea of working on them in a way that it shouldn't corrupt the name. If SET-WORD! gives it a new cache, how do you subvert it?

One way could be to say that SET doesn't do it.

set 'your-func-hi adapt :your-func [print "hi"]

We might make a weird rule, like that SET-BLOCK! with a single element in it is a way to avoid the cache:

[temp]: :some-function

I've contemplated for a while if there's a shade of meaning that a SET-BLOCK! single assignment of a word might have that assigning the word itself would not have. Maybe this is that shade?

I don't know...but just mentioning that I think the cache is moving from SETs vs GETs, and we'll see what the fallout is.

This is still relatively new stuff, and I actually haven't been paying all that much attention to this feature. So there's not a lot of experience with it. I think we need some means of manually updating the label cache for function-building things, and probably some other features...but without people actively giving feedback it's hard to say.