tcl9var

wdb Inspired by If we had no variables, and some ideas found in Tcl 9.0 WishList, I have some day-dreams of getting rid of set, where instead of the procedure set the variable itself is a procedure.

instead of saying

 % set a apple
 apple
 %

we could say

 % tcl9var a apple
 apple
 %

and instead of saying

 % puts "my $a is red"
 my apple is red
 %

we could say

 % puts "my [a] is red"
 my apple is red
 % 

and instead of changing the variable a by saying

 % set a ${a}tree
 appletree
 %

we could say

 % a becomes [a]tree
 appletree
 %

Larry Smith: The Tinker programming language, which is part of my ctools package, does exactly this. This sort of behavior is characteristic of all TRAC-based languages (Tint and others), only Tcl has been different.

I no longer have a website to host ctools, but the Tinker source code in C is less than 700 lines, it could be posted here is anyone is interested in experimenting.

Here is a toy implementation of such behaviour:

 set persistentCounter 0
 array set persistent {}

 proc tcl9var {name value} {
    variable persistentCounter
    variable persistent
    set persistent([incr persistentCounter]) $value
    uplevel 1 [subst {
        proc $name {{cmd get} args}\
            {eval ::handleVar $persistentCounter \$cmd \$args}
    }]
    set persistent($persistentCounter)
 }

 proc handleVar {count cmd args} {
    variable persistent
    switch -exact -- $cmd {
        get {
            set persistent($count)
        }
        set - = - <- - becomes {
            eval set persistent($count) $args
        }
        append - lappend {
            eval $cmd persistent($count) $args
        }
        + - - - * - / - % - ** - 
        < - <= - > - >= - == - != {
            expr "$persistent($count) $cmd $args"
        }
        default {
            eval $cmd $persistent($count) $args
        }
    }
 }

Possibilities -- see source of proc handleVar above. Variables behave like objects.

Consequences -- closures must handle namespace of procedures instead of variables. Differs from current behaviour where procedures defined globally and procedures defined in current namespace are visible.

Incompatibilities with set -- variables and procedures use the same namespace, so it is not possible to give a var the name of an existing procedure. that's a pretty HUGE incompatibility!

Summary -- just a day-dream. (What's wrong with day-dreams? Who said, man will never fly?)


LES By calling it tcl9var, the summary rather becomes scaring the bejesus out of Tcl users who hope this will never replace set in new versions of Tcl.


LV The above is rather anti-tcl, in my mind. The reason why is this- you have three different ways of addressing the object a

 % tcl9var a apple
 % puts "my [a] is red"
 % a becomes [a]tree

Why is this all necessary? What is it that is actually being attempted? Is the idea to make variables objects with methods? If so, then let's call the initial command createvar or varobject or something indicative of the action being taken.

Then there is the [a] vs $a usage. The latter is more common to people than the first. If there are going to be more methods than becomes, then I suppose that it is something that people would painfully become adjusted to. But please, give more details on the benefits you envision. Because right now, I see no benefits, but do see detriments - I don't care to end up typing a lot more characters for no benefit...

wdb Your Line 1 describes creation. Line 2 describes usage. Line 3 describes change of exisiting value. That is why it is necessary.

Usage of [a] vs. $a -- if the dollar sign can be replaced by brackets (truly undispensable), then we have one less cryptic special letter. You say, $ is more common -- if you mean, more used, alright. But more common -- no, I prefer less rules and less syntax.

Your name suggestions: I do not mind. Create better names then my ones. But I had no object orientation in mind. d When appropriate, I use OO, but I am not at all an OO fanatic.

When regarding the truly different opinions to this page, I think that my proposal appears too ... say, radical or dramatic. I am not willed to rule the world. If you think it's a doubtful proposal, just say no to it. That's ok. But without such proposal, the world would be quite boring, wouldn't it?


NEM Added a -exact to the switch, to avoid treating * etc as glob characters. Nicely done -- this is exactly the sort of thing I'd like to see. The main problem, as you state in your "consequences" section, is that procs have local vars, but not local commands. I think Lars H may have suggested proc-local commands at one point, and to my shame I think I thought they were a bad idea!

- RS From 8.5 we can have local procs, sort of:

 proc f y {
    set square {x {expr {$x*$x}}
    apply $square $y
 }

The lambda named square is cleaned up on return But this way of using a variable to hold a lambda runs of course in the opposite direction of using procs to replace variables :^)


GN here is a small XOTcl implementation:

  Class tcl9var
  tcl9var instproc init {{value ""}} {my set _ $value}
  tcl9var instproc defaultmethod {} {my set _}
  tcl9var instproc unknown {args} {my set _ $args}

  tcl9var a 123
  puts [a]
  puts [a 4711]
  puts my-[a]-value
  puts my-[a 1 2 3]-value

depending on the type of the variable, different methods can be provided (e.g. for lists, numbers, whatever)


MJ: This is similar to the slot concept in Self. The Self extension uses slots for both methods and values.

See Also

Getting rid of the value/command dichotomy for Tcl 9