Skip to content

Was dynamic scoping of $0 a mistake? #239

@memreflect

Description

@memreflect

What is the output of the following code?
(Hint: it's not the shell invocation or the name of the script as one might expect.)

`{echo echo $0}

This behavior is documented in the man page:

If, as the most common case, a function variable is bound to a lambda, when the function is invoked, the variable $0 is bound (dynamically, see below) to the name of the function.

It sounds reasonably intuitive, but it's awful in practice, and i'm not the first to be confused by it:

I tried to get the name a script was called by hence I did:

NAME=`{basename $0}

giving me a value of '%backquote' for '$NAME'.

Similarly, the following excerpt from examples/esrc.haahr once worked because fn-%backquote = $&backquote was used, meaning $0 was not set, but %backquote became a normal lambda, leading to the same trouble:

fn -- {
  eval `` '' { $0^p $* }
#want: `` '' { --p $* }
#have: `` '' { %backquotep $* }
}

If one defines fn-if = @ { $&if $* }, then many other examples are broken as well:

# examples/number.es
if { ~ $* *[~0-9,.]* } \
     { throw error $0 $0: invalid character in argument. }
#want: throw error number number: invalid character in argument.
#have: throw error if if: invalid character in argument. }

# examples/friedman/lib/subr.es
if { ~ $* () '' } \
     { * = `{ local (fn-$0 =) $0 } }
#want: * = `{ local (fn-whoami =) whoami }
       # undefine fn-whoami, so whoami(1) is invoked
#have: * = `{ local (fn-%backquote =) whoami }
       # invokes fn-whoami repeatedly, not whoami(1)

The general expectation appears to be that $0 is not dynamically scoped.
Can anybody think of a good reason to retain this confusing behavior?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions