Valid HTML 4.0!

Paul Duffin's Thoughts on the Future of Tcl

This is all stuff from an email discussion we were having. While other parts of the discussion were also very interesting, this is probably the bit that most people who were not in on it would be interested in seeing. For the record, I agree with most of this, by and large. I certainly agree with the ideas behind it.

Donal K. Fellows / Tcl Core Team

What would/should the "Tcl Way" be ?

Everything is a command or a list.

Here are some of my thoughts, actually they are your thoughts which infected my brain many months ago and have only just reached critical mass ;-).

The namespace seperator should be " " not ::. e.g. the following would create a procedure called c in the namespace b which is part of the namespace a.

	proc {a b c} {x y z} {}

Namespace path manipulation could be done using list operations, not special namespace ones.

A command therefore is not a simple word but it is now a list. e.g. the following would call the procedure which was created above.

	{a b c} 1 2 3

The namespace itself should just be a dispatching mechanism for its children namespaces and procedures plus somewhere to store variables, in essence it is a procedure with state. e.g. the following code would also invoke the procedure created above because the command [a] which is also namespace "a" would just invoke the rest of its arguments as a command...

	a b c 1 2 3

Currying of a command, creating a new command by packaging up a command with some arguments should be done by appending those arguments to a command (which is a list). e.g. the following would be just the same as all the above calls.

	set command [list a b c]
	lappend command 1 2
	$command 3

The command resolution process of the sequence

	command word1 word2 ... wordN
would be simply
+------\
|	Is command a list, if so then expand it inline. e.g.
|		command element2 ... elementM word1 word2 ... wordN
+-----< and try again.

	Find the command procedure for command and call it.

Recursively expanding the list may not be the best thing but the only problem that I can think of is that it does not allow a procedure to have a space in it, unless the name is not a valid list. However the consistency that is obtained is astonishing.

Caching of command lookup could still be done, it would just have to be able to cope with also caching any curried arguments.

A Feather enhanced version of the command lookup procedure would be.

+------\
|	Does command support the command interface, if so
|	call it.
|
|	Is command an opaque object which has lost its
|	internal representation (lookup the string rep in
|	a global table), if so then reset its internal rep
|	and call its command interface if it has one, if not
|	error.
|
|	Is command a list, if so then expand it inline. e.g.
|		command element2 ... elementM word1 word2 ... wordN
+-----< and goto.

	Find the command procedure for command and call it.

In fact the list object could have a command interface added to it which just expands and invokes itself and the rest of its arguments.

Major / minor stuff would all be sorted out by this along with the perpetual argument of whether to do

	string::range
or
	string range

So you could for example replace [info] with

namespace eval info {

  proc args ...
  proc body ...
  proc cmdcount ...
  proc commands ...
  proc complete ...
  proc default ...
  proc exists ...
  proc globals ...
  proc hostname ...
  proc level ...
  proc library ...
  proc loaded ...
  proc locals ...
  proc nameofexecutable ...
  proc patchlevel ...
  proc procs ...
  proc script ...
  proc sharedlibextension ...
  proc tclversion ...
  proc vars ...
}

Calling [info] on its own would obviously produce the normal error.

  bad option "?": must be args, body, cmdcount, commands, ..., or vars

Adding new function is as easy as typing.

	proc {info shoesize} {} {}

If a namespace and a proc had the same name then the namespace would be invoked first and the proc would only be invoked if the namespace could not satisfy the command. This would make it easy to modify the behaviour of existing commands.

The only problems that I see with this, other than any that I may have mistakenly ;-) mentioned above are.

How to differentiate between relative namespaces and absolute namespaces ?

Have a ** special ** marker for the global namespace such as {}. So [{} a] would be equivalent to [::a].

' ' does not survive [eval] as well as :: does.

Does not matter for commands as [{a b}] is the same as [a b] anyway and any arguments should be [list] quoted. There is obj -> string conversion but this can easily be avoided by [list] quoting.

Syntactic sugar for [set varname] does not work well.

A simple replacing of :: with " " and {} does not work well as $::a::b(12) becomes ${} a b(12) which will be parsed as three seperate words. ${{} a b(12)} does not work because you can only have scalars within ${..}.

This is a major inconsistency between the way [set] works and the way $ works. [set] simply takes its first argument and that is the variable name.

	set a(12)
	set {a(12)}
	set "a(12)"

All of the above are equivalent. $ on the other hand has first to find the end of the variable name before it can do anything, the algorithm it uses is flawed and results in a lot of confusion.

	set b $a(12)
	set b ${a(12)}
	set b $"a(12)"

All of the above are different, the top returns the value associated with element "12" in array variable 'a'. The next one returns the value associated with scalar variable 'a(12)' and the latter returns the value associated with scalar variable '"a(12)"'.

Solving this inconsistency is very simple and also fixes the problem with a qualified variable. The solution is to make ${...} and $... equivalent to

	[set {...}]

The {} are there because otherwise the outer [] will do substitution on the command first. This avoids a second substitution which would change the semantics of $ too much.

By equivalent I mean that the implementation should actually replace the $... or ${...} with a call to [set].

In practice the implementation will not evaluate the equivalent command above but rather it would either byte compile it in the same way, or invoke it (Tcl_EvalObjv).

This should also make it possible for me to replace [set] and have it affect $... / ${...} in the same way.

Phew.

It should be possible to do most of the above in Feather as I am already hooked into the command resolution process and the Tcl_AddInterpResolvers should allow me to modify the variable resolution process as described above although I am not sure.


Placed online with permission.