More Comprehensible Errors With per-Cell Labeling!

There's been a long-running complaint in the Redbol world that if you don't run a function directly from a WORD! or PATH!, it doesn't know a name for it:

>> append 1 <d>  ; dispatched as WORD!
** Script error: append does not allow integer! for its series argument

r3-alpha>> do compose [(:append) 1 <d>]  ; dispatched as ACTION!
** Script error: -unnamed- does not allow integer! for its series argument

To try and improve on this, Red climbs the stack a bit to find something with a name...but the resulting error is gibberish:

red>> do compose [(:append) 1 <d>]
*** Script Error: do does not allow integer for its series argument

The problem this is showing is that ACTION!s are things that can be known by many names, and when they get "extracted" from a WORD! they lose the label.

Today I did something that's kind of obvious-seeming: to make it so that GET-WORD! and GET-PATH! evaluations cache the name in the action cell instance. This isn't doing anything to the shared data for the action, just poking a pointer to the word's spelling data in the cell.

It's a welcome improvement:

>> do compose [(:append) 1 <d>]
** Script Error: append does not allow #[datatype! integer!]
     for its series argument

>> do compose [(:append/only) 1 <d>]
** Script Error: append does not allow #[datatype! integer!]
    for its series argument

The details of why this would be tricky just relate to the fact that bits don't grow on trees...and the "rules of the game" limit cells to 4 platform pointers in size. To make a long-story-short: while ACTION! "archetypes" can't spare a pointer at this time, ACTION! instances can...and the distinction of whether an action is an archetype or not is made by detecting the properties of the pointed-to-series being a WORD-spelling or action-descriptor-array.

If you write a function that processes a function to create a derived one, you'll need some tools for working with this cached symbol...otherwise you'd lose it just by storing actions in temporary variables. Expect to see a few cases of that. I'll look into it when time permits. But this is already a lot better.

3 Likes

When I saw more room for the trickery I couldn't help myself... frame instances have room even though frame "archetypes" don't. This means a FRAME! cell can remember what action it was for, and with some effort tunnel that back to ACTION!s created from said frame:

>> f: make frame! :append
>> f/series: 1
>> f/value: <d>

>> do f
** Script Error: append does not allow #[datatype! integer!]
    for its series argument

...but wait, there's more...

The best tricks are often the simplest. So what about if GET doesn't update the cached label (at least, not without a refinement)?

>> foo: get 'append

>> do compose [(get 'foo) 1 <d>]
** Script Error: append does not allow #[datatype! integer!]
    for its series argument

This gives you an option. And by having the derived function generators operate in terms of GET when doing machinations on the functions they're working with, the name tunnels through:

>> do compose [(specialize 'append [value: <d>]) 1]
** Script Error: append does not allow #[datatype! integer!]
    for its series argument

And fancy things like POINTFREE (under its new alias) can keep the name:

>> do compose [(<- append _ <d>) 1]
** Script Error: append does not allow #[datatype! integer!]
    for its series argument

This simple-seeming feature is going to make coding with the derived function generators much easier. Pretty awesome, if you ask me.

2 Likes