Roland Illig
Roland Illig

Reputation: 41617

Why does Tcl allow proc names with spaces, but not parameters with spaces?

Just for fun, I have written the following piece of code:

proc "bake a cake" {"number_of_people" {number_of_children}} {
    set fmt "Take %d pounds of flour and %d bags of marshmallows."
    puts [format $fmt "${number_of_people}" ${number_of_children}]
    puts "Put them into the oven and hope for the best."
}

"bake a cake" 3 3
{bake a cake} 5 0

I found it funny that the proc names may include whitespace. I thought that combining this with essentially unused arguments would make it possible to make Tcl programs look very similar to spoken natural language, in a similar way Smalltalk does with its bakeACake forPeople: 3 andChildren: 3, just without the strange colon disturbing the sentences and the unnatural word order.

To explore this idea further, I tried the same pattern for the parameters of the proc, by replacing each _ with a simple space. The tclsh8.6 didn't like it:

too many fields in argument specifier "number of people"
    (creating proc "bake a cake")
    invoked from within
"proc "bake a cake" {"number of people" {number of children}} {
        set fmt "Take %d pounds of flour and %d bags of marshmallows."
        puts [format $fmt "${n..."
    (file "bake.tcl" line 1)

This raised the following questions:

Upvotes: 2

Views: 276

Answers (1)

glenn jackman
glenn jackman

Reputation: 246764

Have a close read at the proc documentation: each of the args in the arg list is itself a list, that must have 1 or 2 elements: the mandatory argument name and the optional default value. "number of people" has too many elements. You can get what you want with just another layer of braces:

% proc "bake a cake" {{"for people"} {"and children"}} {
    puts "baking a cake for [set {for people}] people and [set {and children}] children"
}
% "bake a cake" 1 2
baking a cake for 1 people and 2 children
% "bake a cake"
wrong # args: should be "{bake a cake} {for people} {and children}"

I don't see the benefit of pursuing this experiment: the awkward variable names preclude the $ syntactic sugar.

Note that it's not that difficult to get Smalltalk-looking code

% proc bakeACake {forPeople: nPeople andChildren: nChildren} {
    if {[set forPeople:] ne "forPeople:" || [set andChildren:] ne "andChildren:"} {
        error {should be "bakeACake forPeople: nPeople andChildren: nChildren"}
    }
    puts "baking a cake for $nPeople people and $nChildren children"
}
% bakeACake
wrong # args: should be "bakeACake forPeople: nPeople andChildren: nChildren"
% bakeACake foo 1 bar 2
should be "bakeACake forPeople: nPeople andChildren: nChildren"
% bakeACake forPeople: 3 andChildren: 4
baking a cake for 3 people and 4 children

Although unlike Smalltalk, you can't have other commands starting with "bakeACake" (unless you dig into "namespace ensembles")

Upvotes: 3

Related Questions