Version 8 of Getting rid of the value/command dichotomy for Tcl 9

Updated 2003-04-23 20:12:00

Extracted from Tcl 9.0 Wishlist...


Right now, we have variables (and arrays), and we have commands. Commands are not first-class objects, and can not be passed around as values, other than by coming up with a name for them and passing that around.

What if these things were merged? This touches on what Feather went after, I think. Lisp s-expressions also come to mind.


LV Why not ruminate on what benefits doing this would provide to Tcl 9? For instance, one benefit appears to be moving towards making lambdas possible - which is something that's been discussed in the past as being desirable. Another thing I think I see as I read below is that it may make the major/minor (command/subcommand) support stronger in Tcl. That's another requested goal. Are there other benefits in this refactoring?


So the notation

  proc a {b c} { ... }

would be shorthand for something like

  set a {lambda {b c} { ... }}

Calling this would be done as usual:

  $a 1 2

Now add a touch of syntactic sugar: every first word of a command is treated as a variable name, the value of which is used to supply the code. So the line

  a 1 2

is internally interpreted as

  [set a] 1 2

and then evaluated as it is now. Another way of saying this, is that there's an implicit "$" at the start of each command.

Combined, this would allow the following to work:

  set a {lambda {b c} { ... }}
  a 1 2

And if you think about it: "set" is now a variable too, with the code it takes to do what set always does.

Access in this way has further implications. One can now write

  a(ha) 1 2

which would use $a(ha) as source of the command to evaluate.

Is there a way to generalize this even further? Could "a(ha)" and [list a ha] be synonyms? Would that lead to an even more generic design, which can unify minor/major and namespaces as well?

Lars H - You're quite far out here; in the last paragraph the language has probably stopped being Tcl. (This doesn't mean it is necessarily bad, but it's no longer just a change of dialect.)

male 03.04.2003 - Start:

No, not this kind of merging commands and variables, just because it wouldn't be possible to have variables with the same name than a command! This would restrict a lot! But in general I would like to have "nameless" procs stored in variables and arrays or procs to "carry" around like proc arguments! Examples:

 % set a 1
 % $a
 invalid command name "1"
 % set a {{name} {return "Hello ${name}!}
 % $a Martin
 Hello Martin!
 % set pi {{} {return [expr {4*atan(1)}];}
 % $pi
 3.14159265359
 % proc a {} {return "Hello world!";}
 % a
 Hello world!
 % proc b {procA} {return [$procA];}
 % b a; # calls a as procA
 Hello world!

male 03.04.2003 - End!

The idea to have lambdas is certainly a good one, but unifying the namespaces for commands and variables is a large step that will certainly break many scripts. One could live with it, but I don't see that it would improve on anything. (It would make sense in a language where every token is subjected to variable substitution after it has been parsed -- myVar is treated as if it was $myVar -- but Tcl has never been such a language. Anyone wanting a Tcl-like language of this kind should probably make a fresh start at it, as it would be a very radical language modification.) One should rather accept that Tcl has variables and commands, and that it depends on the context whether a string is looked up as one or the other.

A consequence of that would be that defining a command requires the use of another command than set. If there was an interp define:

interp define path command-name lambda

then

  proc a {b c} { ... }

would rather be a shorthand for something like

  interp define {} a [lambda {b c} { ... }]

(possibly modulo some differences w.r.t. namespace lookup) than a shorthand for the set a sketched above.

Also, it occurs to me that the [$a 1 2] syntax probably is where Feather gets it wrong. It is certainly very nice, but it doesn't work with the language, since in principle any string is a legal command name, including those that are string representations of lambdas. However, if one is prepared to give up on this syntax then everything becomes much simpler. It is only natural to have a command for evaluating lambdas, so one could have something like

  mu $a 1 2

instead of requiring that some values should be given special treatment. When it is a command rather than the core interpreter that says something is a lambda to evaluate, then there is no longer a problem with giving lambdas readable string representations; it could simply be that of the list of the arguments to the original lambda command, or even that command as a whole!

jcw - Agreed - lamda strings are tricky, if there happens to be a command with the same name (possible, not plausible).

Unifying variables and commands is a way of treating everything as a call, or everything as a value, if you prefer. It's what some languages introduce as "properties". This becomes useful when one wants to hide the choice between calculated results and lookups, for example. Or when creating "access proxies" which need to do something special before a value is available (such as fecthing it from another machine). Some of that can be tricked with traces on variables/arrays, but why have three mechanisms where one might suffice?

I don't quite go along with the comment that this has stopped being Tcl. The "a 1 2" notation is just as much Tcl as it is now, the only thing that has changed is the evaluation logic. And the fact that commands, variables, and namespaces might be unified a bit (perhaps not fully, I'm stretching it for the sake of argument). Oh, and that's just half the story - how about unifying file names, package names, and namespaces? It's not far-fetched - Python did that from day one, without loss of expressive power.

Oh well, just ratting the cage a bit... :)

Lars H: It occurs to me that the way to introduce radical language modifications of this type is to introduce a new type of interpreter. Since procedure names, variables, namespaces etc. are all local to the interpreter, one can have one set of the rules for these in one interperter and a completely different set of rules in another. There would be an interp newstylecreate command for creating a slave interpreter with the new set of rules, and such new style interpreters would conversely have a command for creating a slave interpreter with the old set of rules. One could have command-line switches for specifying which style of interpreter the shell starts up with.

(I'm still not particularly suggesting that one should try to unify variables and procedures as outlined above. My point is that I think the cleanest way to do that would be to introduce a new kind of interpreter.)


TV apr 3 03: Apart from rattling the cage thoughts, there is the question of whether one can get out, and it seems to me that the above primarily is not in that range. Making a lambda function in tcl could work, which is essential, except one may be interested in multithreading transparency and namespace neatness. A procedure is a special list, but it can be read and written, albeit that one has to use the

 info args procname
 info body procname
 info defaults procname

constructs. - RS: See Procs as data structures which exploits this feature.


Category Suggestion