Do Functions Know Their Own Names?

Going back a long way when John Scholes and I were writing version 0 of Dyalog there was a big discussion about whether functions knew their own names. This discussion still surfaces, with John taking the side that they don’t and me taking the side that they do.

Essentially, John would argue that after A←2, the “2” does not know that it is called “A”. So after (in modern parlance):

      add←{
          ⍺+⍵
      }

the part in {} does not know that it is called “add”.

The real question here can be put in different terms: Is the symbol + representing the addition function itself or is it one of the possible names of the addition function.

From an APL perspective, does this matter? Most of the time it makes no difference. However, when you view your SI stack it does. Consider:

      add←{
          ⍺+⍵
      }
      times←{
          ⍺×⍵
      }
      inner←{
          ⍺ ⍺⍺.⍵⍵ ⍵
      }

Now if we trace into

      1 2 add inner times 3 4

and stop on inner[1] what do we want to see when we type ⍺⍺ in the session. There are two possibilities:

Either you see:

{
    ⍺+⍵
}

or you see:

∇add

Which of these is more useful?

Being more provocative, try putting the functions in a capsule:

[0] foo
[1] 1 2{
[2]     ⍺+⍵
[3] }{
[4]     ⍺ ⍺⍺.⍵⍵ ⍵
[5] }{
[6]     ⍺×⍵
[7] }3 4

and repeatedly trace until [6]:

      )SI
#.foo[6]*
.
#.foo[4]
#.foo[1]

Compare this with the following:

[0] goo
[1] add←{
[2]     ⍺+⍵
[3] }
[4] inner←{
[5]     ⍺ ⍺⍺.⍵⍵ ⍵
[6] }
[7] times←{
[8]     ⍺×⍵
[9] }
[10] 1 2 add inner times 3 4
      )SI
#.times[1]*
.
#.inner[1]
#.goo[10]

In my view, the latter is much more communicative in a debugging environment.

Going back to the version 0 discussion: We didn’t have dfns or dops, so everything was traditional. The discussion was centred around:

∇r←a add b
[1] r←a+b
∇

∇r←a times b
[1] r←a×b
∇

∇ r←a (f inner g) b
[1] r←a f.g b
∇

Now trace this:

      1 2 add inner times 3 4

until at times[1]

The key question at the time was whether )SI should show this:

      )SI
#.times[1]*
.
#.inner[1]

or this:

      )SI
#.g[1]*
.
#.inner[1]

We choose the first of these options as more informative.

So naming things is good and using those names when reporting state information is also good. When the issue was disputed, David Crossley (who was managing the development of Dyalog) resolved it using the argument about the )SI output.

These days it might not be so obvious. In those days we were essentially thinking in terms of a scrolling paper terminal. It pre-dates the full screen experience that even the tty version gives you. We had to wait for Adam Curtis to join the team before we got that. With the context display whilst tracing there is a stronger argument that the eyes using the debugging information do not need the names. Whilst I admit to the weakening I don’t think it actually changes the balance of the case.

We use a lot of C macros in the interpreter. On Linux, gdb gives us access to those macros when we debug the C code – lldb on MAC, dbx on AIX and Visual Studio on Windows all do not have that information and are, therefore, far less helpful.

8 thoughts on “Do Functions Know Their Own Names?

  1. This is an area that I expect we will do significant work on this summer, as we look more closely at creating new tools to help build and deploy Dyalog applications, with increased focus on using Unicode text files as source. When debugging these applications, you need to know not only the name of a function, but ideally also “from whence it came”, so that the system can write modifications back to the original source file. If anything, the system needs to know more about the “names” of things than ever before, if we want to provide the best possible debugging experience. Naming things is an important tool of thought (if you get it right ;-)).

  2. This discussion seems to provide more questions than answers:

    . how do you trace into a dfn within another function.
    . Is there a consistent rule for choosing ‘times’ over ‘g’ … most global name, most local one?
    . Has the example Perl gives been applied here, i.e. using internal names for unnamed entities.
    . JavaScript also allows for unnamed functions; how does their debugging environment handle those cases?

  3. You can trace into any multi line dfn by hitting the <TR> key. Or on Windows or RIDE by pressing the icon.

    You cannot trace into a single line dfn. This is down to restartability issues. Currently, Dyalog can only restart a “line”.

    Token tracing may come but don’t hold your breath.

    Dyalog is not consistent about the naming – I did say that John and I disagreed on this aspect. For tradfns the name is allocated by the ⎕FX (the editor uses ⎕FX) and persists for the life of the function. For nested dfns I can’t be that dogmatic.

  4. While my implementing APL concepts in Forth transparent down to the silicon is still incredibly primitive ( and incomplete ) its fundamental structure , simplified from K , associates names and their values ( which may be functions ) thru a pair of lists . Thus objects and their associated names are very distinct objects .

    Arthur’s “dictionaries” have 3 correlated lists , the third being an “attribute” list . I found it too complicated to reference from an item in one list back to its associated items in the other lists so I added a “meta” pointer to object headers so the current structure is

    ( type ; count ; ( refs ; bitsPerItem ) ; meta ) followed by the data .

    ` meta may be used as a pointer to a dictionary ( ~ namespace ) incorporating what would be in Arthur’s attribute column . One item I’ve contemplated may be a useful useful to include in attributes would be the name associated with an object .

    But I find little time to mess with things at this level , tho I use 4th.CoSy as my everyday log . It’s a tortoise , but it’s my tortoise , others welcome to it .

  5. I think the
    #.times[1]*
    is much better than the
    #.g[1]*
    in the SI stack for two reasons:
    1) “times” has a more global scope, searching the workspace for “g” would be far less useful.
    2) Clicking on “times” with the mouse will edit, it.
    Clicking on “g” bring up the “Readonly Function” with
    [0] # . ∇times
    requiring a second mouse click to edit (or view) its contents.

    Under static analysis of the workspace, the fact that the times function is sometimes called via a reference call “g” is of very little use. Another call of “inner”, “g” could refer to something completely different.

  6. The key question at the time was whether )SI should show this:

    )SI
    #.times[1]*
    .
    #.inner[1]

    or this:

    )SI
    #.g[1]*
    .
    #.inner[1]

    We choose the first of these options as more informative.

    So naming things is good and using those names when reporting state information is also good. When the issue was disputed, David Crossley (who was managing the development of Dyalog) resolved it using the argument about the )SI output.
    ——————————-
    So why did Mr.Crossley choose the name binding “times”, which is not local to “inner”? What would he do if “inner” had a local function named “times”? What about if a different alias of “times” had been the one actually passed to “inner”? Are you retaining an audit trail of which bindings were dereferenced to produce the object on your )SI? No, I didn’t think so… quit trying to read your users’ mind and just report the raw facts.

    On that subject, why not report the active function as #inner.g[1] by using a fully-qualified name of the binding by which it was activated?

  7. The function/operator acquires its “name” when it is defined. That name persists over function assignment or use as an argument. So:
          ⎕FX'r←a plus b' 'r←a+b'
    generates a function with name “plus”.
          addition←plus
    gives another name for the same function but it still thinks its name is “plus”.

    In some ways this is analogous to the display form of a namespace although we don’t give you a mechanism with which to change it.