Simplification of the Tcl language

LEG 20081209:

Multiple Return Values

Are discussed in the page Everything is a list

blocks/loops with progn functionality

I want for foreach and while to evaluate to the value of the last executed command.

I want break accept (multiple) arguments just like return (as in Multiple Return Values)

Extensive use of variadic functions

One of the nice things about Tcl is, that lot's of its commands take an arbitrary list of arguments and do something sensible with them. If the return values of commands could also be variadic (see Multiple Return Values), we could stack and stack and stack and ... one command on the other easily.

The following are some salvage ideas for modified Tcl commands.

'What if

  • All commands for which it is sensible process an arbitrary length argument list.
  • All commands for which it is sensible returns a list. See examples.
  • A new command "args" is introduced, it is used for args expansion.

Examples for list aware commands:

set v
return the value of v
set v args
set v to the list created by concatenation of all args and return it
puts ?-chan channel? ?-nonewline? ?args?
concatenate all args and write them to channel. default channel is stdout
gets args
each arg is a channel, get a line from each of them and return a list in the order of the channels. if args is empty get a line from stdin
close args
close all channels
return ?-code code -errorInfo info -errorcode code? args
concat all args and return them
incr args
interpret args as list of varName increment pairs. return list of incremented values. If the list has an odd number of arguments, the last variable will be incremented by 1.
array exists args
args is a list of arrayNames returns a list of flags for existence of each arrayName
array get -pattern patternList args
args is a list of arrayNames it returns a list of {key value} pair lists, which are the matches of each pattern of patternList in the respective arrray

Playground

Variadic versions of typical Tcl commands are implemented with the same name with a '*' at the end.

proc args {} {uplevel set args}
proc return* args {
    set opts {}; set i 0
    foreach {o v} $args {
        switch -exact -- $o {
            -code - -errorinfo - -errorcode {
                lappend opts $o $v; incr i 2
            }
            -- {incr i}
            default {break}
        }
    }
    uplevel return $opts [list [lrange $args $i end]]
}
proc set* {varName args} {
    uplevel set $varName $args
}
proc puts* args {
    set opts {}; set i 0
    set chan stdout
    foreach {o v} $args {
        switch -exact -- $o {
            -chan {set chan $v; incr i 2}
            -nonewline {
                lappend opts -nonewline
                incr i
            }
            default {break}
        }
    }
    foreach e [lrange $args $i end] {
        uplevel puts $opts $chan [list $e]
    }
}

proc retThree {} {return* 1 2 3}
proc retOne {} {return* {1 2 3}}
proc returnOne {} {return {1 2 3}}
proc retMany args {return* {*}[args]}

puts* "puts* retThree:" {*}[retThree]
puts* "puts* retOne:" {*}[retOne]
puts* "puts* returnOne:" {*}[returnOne]
puts* -nonewline "puts* -nonewline returnOne:\\n\n" {*}[returnOne] \n
puts* "puts* retMany a b c d" {*}[retMany a b c d]