Updated 2017-06-01 19:32:29 by pooryorick

Everything is a Constructor is an idea for the improvement of Tcl in which additional information about values is given first-class status.

Description  edit

PYK 2017-06-01:

EIAS is a principle of the current Tcl implementation in which every argument to a command is interpreted as if a certain literal string had been passed as the argument. In fact, Tcl processes words in a command for substitutions before it passes them to a routine, but any information generated by this processing is subsequently only used in a way that is semantically equivalent to the processing that would have occurred had a corresponding string with no additional information been passed. This means for example that in order for puts to take as its optional argument either a channel or a file name, it would have to devise some string format to differentiate a channel from a file name. Since a file can have an arbitrary name, this can't be done.

In Tcl 8.5, a new processing directive was was admitted at the script level and it was implemented as a change to the syntax: A literal {*} in a script at the beginning of a word tells the interpreter to unpack that word into multiple words, which has the effect of expanding the number of arguments handed to a routine when it is called. This is a welcome bit of functionality, but did it have to be a syntactic change to Tcl? One thing that seems to be conspicuously absent from the discussions that led up to the implementation of {*} is any substantive proposal to accomplish the task by inspecting the internal representation of the value. Rather than introducing new syntax, a command which returned an "expand me" value could have been introduced:
set [expand {name Bob}]

This approach harmonizes with the principle that nearly all functionality is exposed in terms of commands. Commands such as lreplace, operate this way, using any existing list structure to get the job done more efficiently. The same trick can be used to allow the interpreter to perform argument expansion.

The very existence of Rule 5 illustrates the flexibility that the interpreter has in this regard. That flexibility could be better articulated by making small change to the wording of Rule 2:
..., then all of the words of the command are passed to the command procedure.

, Rule 2 could have been modified to say,
..., then the resulting values are passed as arguments to the command procedure.

Eliminating that second use of "word" to describe the result of the substitutions makes it clear that words are processed into arguments to the routine, and since Tcl itself is in charge of the creation and use of these processed values, it is free to put them to work. Everything is a Constructor conveys the idea that while the words in a command produce the values in a Tcl script, but they are not in themselves the values.

If values rather than words are the arguments to a routine, commands can relax in regards to EIAS. In the earlier example, puts could inspect its optional second argument to determine that it is in fact not a channel, and then treat it as a filename instead.

is  edit

string is is currently available to determine whether a string representation of a value conforms to a certain format. Once words and values are no longer being conflated, a similar command, perhaps named is, could be introduced to provide a system for inspecting the value itself:
is value1 value2
Returns true if value1 is the same type of value as as value2, and false otherwise.

extensions that provide their own value types could use some implementation-level mechanism to register a function for is to use when it encounters values of that type . A procedure could use is to condition its operation on these comparisons. For example, an enhanced puts procedure might look like this:
proc newputs args {
        set opened 0
        if {[llength $args == 1]} {
                set target [chan lookup stdout]
        } elseif {[llength $args] == 2} {
                lassign $args target string
                if {![is $target [chan type]]} {
                        set target [open $target w]
                        set opened 1
                }
        }
        try {
                ::puts $target $string
        } finally {
                if {$opened} {
                        close $target
                }
        }
}

chan type returns a value to be used only by is, and not for any real channel operations. For other values such as lists, list could be used:
if {[is $somevariable [list]]} {
        puts {found a list}
}

Also needed in the example was [chan lookup stdout] which returns the corresponding channel value based on a name.

To Be Continued  edit

That's it from now. More to come.