Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Seeking Comment on Tip#479 - Named Parameters For Procs

395 views
Skip to first unread message

Hypnotoad

unread,
Oct 25, 2017, 11:21:00 AM10/25/17
to
I am currently seeking input on an alternative to tip#451, tip#479.

Tip 479:
* Uses a dict based description for named parameters
* Provides a new command to define procedures with only named parameters (@procs)
* Only allows named parameters in place of args for standard procs
* Makes the parser facilities available as a command (@args)
* Provides a new keyword to TclOO (@method) to define methods that accept named parameters

The full writeup is on the project fossil repository:

http://fossil.etoyoc.com/fossil/tip479

The index page mirrors the text on the official tip entry:

http://core.tcl.tk/tips/doc/trunk/tip/479.md

The patch to the core is ongoing, but a a pure-tcl mockup and a TEA extension are available for evaluation using a standard 8.6 interpreter.

--Sean "The Hypnotoad" Woods

jm....@orens.fr

unread,
Oct 25, 2017, 3:31:11 PM10/25/17
to
Hello Sean,

I've read TIP #479 and TIP #457 (<> #451):

Please disambiguate in what "named arguments for proc" adresses a different need from "namespace ensemble" usage.

If a direct reading/"quick code review" of argument passing is needed, I'll have no pb to do this :

set option1 1
set option2 2
...
set optionx x

then call "exampleproc" proc with :
exampleproc $option1 $option2 .... $optionx

Small discipline is involved in naming/managing global varnames ([unset -nocomplain] or namespaces can help here).

But it's possible I misunderstood the point.

Specifically about TIP 479, difficult (for me) to read :

How would the four following lines "translates" in TIP 479 format :

8<-----------------------------------
proc exampleproc {val1 val2 val3} {
puts "$val $val2 $val3"
}
exampleproc 1 2 3
----------------------------------->8

Regards,

-jm

Hypnotoad

unread,
Oct 25, 2017, 3:57:45 PM10/25/17
to
Thanks for the reply jm,

In the simplest case nothing would change. proc continues to work with positional arguments the same way.

What both tips address are cases where we need to be flexible about the order in which arguments arrive:

8<-----------------------------------
@proc exampleproc {
val1 {}
val2 {}
val3 {}
} {
puts "$val $val2 $val3"
}
exampleproc val1 1 val2 2 val3 3
----------------------------------->8

In tip#479. The empty set next to each argument is actually a dictionary that allows the developer to
ascribe behavior to the arguments. Set a default value if not given, or state whether a variable is
mandatory or not.

The new behavior complicates simple procs, but if you have a procedure that takes in a number of
parameters, and if that proc has a habit of changing and/or needs to accept incomplete input,
having named procedures can be essential.

The tip also allows you to mimic Tk's metaphor:

8<-----------------------------------
proc my_psuedowidget {path {args {
color {default blue aliases {-color -bg}}
flavor {default vanilla aliases -flavor}
borderwidth [default 0 aliases {-bd -borderwidth}}
}} {
label $path -text $flavor -color $color -bd $borderwidth
}
my_psuedowidget .label -flavor mango -bg purple -bd 10
----------------------------------->8

The tip also provides and arg eater called @args which can be nice for inside of ensembles.

8<-----------------------------------
proc dispatch {command args} {
switch $command {
smtp {
# Dicts can be created on the fly
@args [dict create from {} to {} mtime [dict create default [clock seconds]]] $args
smtp::dispatch $from $do mtime $mtime
}
http {
# Or accept a static string with whitespace
@args {
from {}
to {}
subject {}
url {default http://mydomain.info}
} $args
http::post ${url}?from=${from}&to=${to}&subject=${subject}
}
}
}
----------------------------------->8

Since the tip also builds on that args mechanic, you can also do dict processing for optional (or unexpected) parameters.

8<-----------------------------------
@proc pedantic {
from {}
to {}
subject {}
} {
set fields [dict keys ${@spec}]
foreach key [dict keys $args] {
if {$key ni $fields} {
error "Unknown parameter $key. Valid: $fields"
}
}
}
8<-----------------------------------

In the above case, if the user feeds in a field other than to, from or subject the proc will throw an error.

sled...@gmail.com

unread,
Oct 26, 2017, 12:00:16 AM10/26/17
to
Having trouble seeing the need for this beyond being a 'nice to have'.
Seems one could within a script establish an array with param\default values (e.g parms(-flavor) chocolate); then perform an array set parmarray $args. That's seems to manage names params, missing params, defaults, extraneous parms, etc.

So what am i missing.

jm....@orens.fr

unread,
Oct 26, 2017, 12:03:41 AM10/26/17
to
Thanks Sean, now I understand better.

Your examples are very interesting, thanks.

I however am not a big fan of your proposal : lot of braces -> not nice

+ difficult to love having to specify "I specify nothing" with usage of {} too.

Not good if developper must deal with hierarchical nested logics representations -> the effect goes away fron needed simplicity.

-jm

Georgios Petasis

unread,
Oct 26, 2017, 12:59:19 AM10/26/17
to
I need named arguments in Tcl. The use case is obvious, think as a
public api for any application: you have 10 arguments (i.e. because you
are calling a machine learning algorithm), all of them have default
values, but you don't expect the caller to specify again 8 default
values to change the 9th.

I really like the way python has them, but I don't know how they can be
added to Tcl. Perhaps we need to introduce some new syntax, like {*}?

George

jm....@orens.fr

unread,
Oct 26, 2017, 5:32:22 AM10/26/17
to
Hello George,

I agree with you George, and after better understanding, as previously mentioned, I now support "named arguments" too.
But additional research/effort are needed to not go away from simplicity.
By curiosity, I looked for how does Python in this area.

http://www.diveintopython.net/power_of_introspection/optional_arguments.html

If this level of quality can't be reached, I'm not a big fan for this.

Regards,

-jm


Hypnotoad

unread,
Oct 26, 2017, 8:30:09 AM10/26/17
to
I would like to point out that Python implements their optional arguments as dicts. And this proposal is trying to do the same with Tcl.

Using the patterns from the example, in Python:
info(odbchelper)
info(odbchelper, 12)
info(odbchelper, collapse=0)
info(spacing=15, object=odbchelper)

In Tcl they would be:

info odbchelper
info odbchelper 12
info odbchelper collapse 0
info spacing 15 object odbchelper

Except, of course, python don't seem to be particular about mandatory positional arguments. Which is why the article is trying to talk users off the ledge by convincing them its so "simple."

To implement that mess in Tip#471 you would have to get a little fancy:

proc info args {
switch [llength $args] {
1 { lassign $args object }
2 { lassign $args object spacing}
default { @args {object {}} $args }
}
# The working bits of "info"
}

The problem is that for all that "flexibility", good luck in producing any kind of introspection. [info args] Will just tell you "args". Any introspection that @proc could capture is non-existent because we don't declare any kind of structure to our arguments.

We *can* do that. But one of the reason I program in Tcl is because I want someone to be able to read the code when I'm done with it.

Hypnotoad

unread,
Oct 26, 2017, 8:52:13 AM10/26/17
to
One of the design goals of Tip#479 was to re-use as much if the existing infrastructure from Tcl as possible. In that, the argument spec for @proc is a dictionary. Anything that can populate a dictionary can feed @proc and the new spec argument for args. Any additional fields beyond default, variable, aliases, and (when tip#480 comes to pass type) are ignored but @args, but can be accessed from within the proc.

Let us say that we have a datatype system built into our larger program. We can use those datatypes to inform the procs and methods in our prospective application.

::oo::define myclass {
set options {
path {}
color {variable color aliases {-color -bg} default white}
flavor {variable flavor aliases -flavor default random options {vanilla chocolate strawberry}}
}
method options {} [list return $options]

# Arguments can be a dict from any source
@method new_label $options {
if {$flavor eq "random"} { set flavor [lrandom [dict get ${@spec} flavor options]] }
label $path -bg $color -text $flavor
}

# We can re-use them
@method new_button $options {
if {$flavor eq "random"} { set flavor [lrandom [dict get ${@spec} flavor options]] }
button $path -bg $color -text $flavor
}

# And modify them on the fly
set entryopts [dict merge $options {
variable {aliases textvariable default {} comment {Variable to store data}}
}]

@method new_entry $entryopts {
if {$flavor eq "random"} { set flavor [lrandom [dict get ${@spec} flavor options]] }
set cmd [list entry $path -bg $color]
if {$variable ne {}} {
lappend cmd -textvariable $variable
}
{*}$cmd
}
}

jm....@orens.fr

unread,
Oct 26, 2017, 11:19:25 AM10/26/17
to
Thanks Sean, for your explanations.

I understand there is hard work done for this and recognise the effort to keep tcl well known semantic.

My previous words "this level of quality" were too strong and should be replaced with "this level of apparent simplicity".

My position is not technical as I'm not expert, but on practical usage.

As a tcl user, I must recognise (shame on me) that my eyes much prefer to read :

"info(odbchelper, collapse=0)" <-as opposed to-> "info spacing 15 object odbchelper"
idem for :
"info(spacing=15, object=odbchelper)" <-as oposed to-> "info spacing 15 object odbchelper"

The reason is that in expressions on the left side, the equality symbol makes an easy to read relationship between two related elements, and the comma separator is a visual aid for grouping semanticaly related elements together. By contrast, on the right side, I have to count each element, mentaly determining from its position(*) if it is a command, a key, or a value.
(OK my eyes are often tired so visual aid is appreciated).

The pb doesn't exist for short lists, but when having to read unknown lists of more than 8 elements, I'm sure to have a least 50% chance of mistake if I have to determine with accuracy, in a glimpse, ordinal position of a "centraly positionned" element.

(*) I wonder if this does'nt contradict "position independancy" first intention of named aruments

Regards,

-jm

Xcott Craver

unread,
Oct 26, 2017, 2:03:34 PM10/26/17
to
Hi,

Beyond the performance issue, how would this functionality be different from:

proc drawme args {
array set {} {-width 800 -height 400 -color red} ;# defaults
array set {} $args

# .... your code

puts "Canvas will be $(-width)x$(-height), and $(-color)"
}

drawme -color blue

I've used variations on this trick a few times, although exposing it to
others as an interface usually requires a bit more sophistication and
error handling.

--
==
"Taking jokes seriously is the exact mirror activity of laughing if
someone says they have cancer." --jbou

Hypnotoad

unread,
Oct 26, 2017, 3:25:37 PM10/26/17
to
In tip#479 that same code would be:

@proc drawme{
-width {default 800}
-height {default 400}
-color {default red}
} {
# .... your code
puts "Canvas will be ${-width}x${-height}, and ${-color}"
}
drawme -color blue

If you don't like the local variable names that pattern produces:
@proc drawme{
width {default 800 aliases -width}
height {default 400 aliases -height}
color {default red aliases -color}
} {
# .... your code
puts "Canvas will be ${-width}x${-height}, and ${-color}"
}
drawme -color blue


1) The code for @args is actually faster. Partly because it manages to do in one call to C what takes several lines of Tcl, partly because the routine is just that simple.
2) Instead of writing to an array, local variables get populated.
3) @args can throw errors if an argument is missing
4) @args can interpret aliases for flags
5) @args and can have a parameter map to a variable that has a different name.

Also, this mechanism will eventually provide a nice report somewhere in [info] to tell you what parameter it accepts. But that won't be until stage 3 of the project when we start attaching the data structure to the proc.

I agree this is an obvious design pattern. That's part of the joy.

Hypnotoad

unread,
Oct 26, 2017, 3:27:58 PM10/26/17
to
On Thursday, October 26, 2017 at 2:03:34 PM UTC-4, Xcott Craver wrote:
Apologies, I had a typo in the second example:

If you don't like the local variable names that pattern produces:
@proc drawme{
width {default 800 aliases -width}
height {default 400 aliases -height}
color {default red aliases -color}
} {
# .... your code
puts "Canvas will be ${width}x${height}, and ${color}"
}
drawme -color blue

Another way to express it:
@proc drawme{
-width {default 800 variable width}
-height {default 400 variable height}
-color {default red variable color}
} {
# .... your code
puts "Canvas will be ${width}x${height}, and ${color}"
}

Hypnotoad

unread,
Oct 26, 2017, 3:37:15 PM10/26/17
to
It hadn't occurred to me that having a stream of key/values is actually a pain to decipher. But you are right!

The nice thing is that if the developer wants to put some pretty delimiters in, or adopt a JSON like marker for fields, that is perfectly legal in tip#479

info object: odbchelper spacing: 12

With:
@proc info {
object: {variable object}
spacing: {variable spacing}
} { ... }

OR

info -object odbchelper -spacing 12

@proc info {
-object {variable object}
-spacing {variable spacing}
} { ... }

And the "variable" property would only be needed if you didn't mind internal variable starting with a dash (-) or ending with a colon (:).

My concern with the equal sign is that, while it does bridge the key and the value visually, it's something we are going to have to chop out and ignore later. There is also the problem of values that contain an "=" character, which means that you have to escape out any text strings in a non-standard tcl notation. Going with key / value pairs broken up by the conventional rules for Tcl dicts simplifies the implementation.

That may not be the prefect answer, but that's my story and I'm sticking with it.

Thanks for the feedback though, you raise a really good point.

--Sean

paul...@googlemail.com

unread,
Oct 27, 2017, 2:15:41 PM10/27/17
to
On Thursday, October 26, 2017 at 8:27:58 PM UTC+1, Hypnotoad wrote:

>
> If you don't like the local variable names that pattern produces:
> @proc drawme{
> width {default 800 aliases -width}
> height {default 400 aliases -height}
> color {default red aliases -color}
> } {
> # .... your code
> puts "Canvas will be ${width}x${height}, and ${color}"
> }
> drawme -color blue
>
> Another way to express it:
> @proc drawme{
> -width {default 800 variable width}
> -height {default 400 variable height}
> -color {default red variable color}
> } {
> # .... your code
> puts "Canvas will be ${width}x${height}, and ${color}"
> }

My first impression is that the above looks like a useful feature, a bit more than a nice to have. I guess I didn't like the @ too much though, and thought that something like

proc -namedargs drawme {
-width {default 800 variable width}
-height {default 400 variable height}
-color {default red variable color}
} {
...
}

would be more in line with what I'm used to with Tcl. For example, to do a puts without a new line, I write puts -nonewline hello, rather than eg @puts hello. Just my 2c :)


Xcott Craver

unread,
Oct 27, 2017, 3:24:12 PM10/27/17
to
On 2017-10-27 18:15:39 +0000, paul...@googlemail.com said:
>>
>
> My first impression is that the above looks like a useful feature, a
> bit more than a nice to have. I guess I didn't like the @ too much
> though, and thought that something like
>
> proc -namedargs drawme {
> -width {default 800 variable width}


I like that idea. We could make it with the standard arglist, like
these examples:

% proc -namedargs drawme {width: height:} { puts ${width:} }

% drawme height: 30 width: 20

% proc -namedargs drawme {-width -height} { puts ${-width} }

% drawme -width 20 -height 20

% proc -namedargs drawme { {width -width width:} {height -height
height:} } { puts $width }

% drawme width: 20 height: 30
% drawme -width 20 -height 30
% drawme width 200 height 300

...so unlike a proc arglist { {x 30} y } where an inner list specifies
a name and default arg, we'd have a proc -namedargs arglist { {x alias
alias} y }, where the first entry is the variable name used in the proc
body, and the rest are argument aliases.

Then you can allow a default arg with some extra bit of syntactic cruft, like

% proc -namedargs drawme { width -default 30 {height height:} -default
20 } { #body }

or

% proc -namedargs drawme { width<30> {height<20> -height height:} } { #body }

jm....@orens.fr

unread,
Oct 29, 2017, 2:17:37 PM10/29/17
to

I like this :

> % proc -namedargs drawme { width -default 30 {height height:} -default
20 } { #body }

However it combines not too well with :

> % drawme -width 20 -height 20

as in this case drawme definition would have to be :

proc -namedargs drawme { -width -default 30 {height height:} -default 20 } {#body }

Wich make arise a need of disambigation between langage provided options from application provided options.

But if it is considered that default values for "proc with named parameters" is a mandatory constraint (as mentionned in TIP 479, but not super clear to me), then things can be simplified :

proc -namedargs drawme {width -default 30 {height -height height:} -default
20 {color -color bg} -default blue} { #body }

can become (for example) :

proc -namedargs drawme {width {30} height {20 -height height:} color {blue -color bg}} {
#body }

Here, arguments definition is a list of key-value pairs where first element is the one used in body, the second element is itself a list with at least one element, the mandatory default value, eventually followed by aliases.

There, braces give me an aid to separate easily keys from values.


-jm

Braden Napier

unread,
Oct 29, 2017, 5:30:09 PM10/29/17
to
Another option which you guys may enjoy is found here: https://wiki.tcl.tk/49081 with a pure-tcl implementation.

jm....@orens.fr

unread,
Oct 30, 2017, 7:04:10 AM10/30/17
to
Le dimanche 29 octobre 2017 22:30:09 UTC+1, Braden Napier a écrit :
> Another option which you guys may enjoy is found here: https://wiki.tcl.tk/49081 with a pure-tcl implementation.
>

Hello Braden,

Thanks for sharing. Your analysis on options as a specific subset in arguments'world is very interesting.
I can't share a lot about this as my practice of proc is pieces of code with only one code path inside its body if possible. This helps me to keep clear idea of what a specific proc does.
However, your package is worth to be aware of, as in some situation it may provide an usefull option :)

Regards,

-jm

Matthew Hiles

unread,
Oct 30, 2017, 2:04:45 PM10/30/17
to
This is how I solved the named argument problem:

package provide named_args 0.1

proc get_args {} {
upvar args a
set positional_args {}
foreach element $a {
if {[string match -*=* $element]} {
set val [lassign [split $element =] key]
upvar $key lkey
set lkey $val
} else {
lappend positional_args $element
}
}
set a $positional_args
}


Then you can do

proc testproc {args} {
get_args
set leftover [lassign $args arg1 arg2]
}

testproc -key=somevalue -key2=$substution_works

No, it's not perfect and there are several corner cases that won't work. But I find it integrates well and is very little overhead. You can't specify mandatory arguments and defaults are not handled--it's pretty bare bones, but again for what I use it for it works well.

Andreas Leitgeb

unread,
Oct 30, 2017, 3:46:05 PM10/30/17
to
Matthew Hiles <matthe...@gmail.com> wrote:
> This is how I solved the named argument problem:
> [...]
> No, it's not perfect and there are several corner cases that won't work.
> But I find it integrates well and is very little overhead. You can't
> specify mandatory arguments and defaults are not handled--it's pretty
> bare bones, but again for what I use it for it works well.

If it works for you, that's fine.

Here are reasons, why it might not be working well for others:

- it will destroy performance to a ways higher degree than
all the other suggestions so far, because every value passed
to such a proc will be stringified by appending it to "-key=".
(Since Tcl8.0, Tcl can do better than always deal with strings)

Even if some big argument does not get appended to some "-key=",
the "string match"-test will still stringify it.

That may or may not matter.

- it doesn't deal well with another "=" char in the value.

That could probably be fixed: set lkey [join $val =]

Btw.:

+ defaults *are* handled: just set the param to a value before
calling get_args.

Hypnotoad

unread,
Oct 30, 2017, 5:42:10 PM10/30/17
to
Just an update, a core implementation patch has been submitted to fossil and you can now build tip-479 at home. It tracks with the current Tcl trunk, but it could be easily back-ported to Tcl8.6 (and probably Tcl 8.5).

http://core.tcl.tk/tcl/timeline?r=tip479

While the @args command is available for custom argument handling inside of procs, the means to do named arguments within the core is more elegant. If "args" is given a default value (previously ignored) that is now a specification for named arguments. And those named arguments are gobbled up and delivered as local variables in roughly the same manner as formal arguments. @proc is now simply a macro:

proc @proc {name argspec body} { proc $name [list [list args [dict create {*}$argspec]] $body }

Another item that fell out of the implementation was the mapping of a foreign variable. It is now assumed that the name in the spec is the name you want to see the variable on the inside of your procedure. If you want to accept other names, use the aliases option.

Hypnotoad

unread,
Oct 30, 2017, 5:53:58 PM10/30/17
to
Next on my list is the means for API writers to hijack the Tip 479 implementation in a non-expensive way to implement their own grammars and options.

For instance, a psuedo tip457 parser:

proc myproc {name args} {
# The body is always the last argument
set body [lindex $args end]
set normarg {}
set argspec {}
# Your parser implementation here
# Fill in argspec
set finalbody {}
# Append to finalbody any sugary goodness you need to do beyond tip 479
append finalbody \n $body
# Formulate into baked proc
proc $name [list {*}$normarg [dict create args $argspec]] $finalbody
}

jm....@orens.fr

unread,
Oct 31, 2017, 7:27:38 AM10/31/17
to
As a follow up of my post of october 29, bellow is an idea trying to adress, from a user POV, of a possible simple way to specify argument input enforcement at call time (inspired from NOT NULL constraint in SQL langage) + without changing the rule that defaults definition is mandatory (motivated by readability/simplicity).

The idea relies on a new and independant option of proc command, introducing a contraint in its definition, checking against empty string assigned to any local variable representing arguments.

So bringing back drawme proc (slightly modified) example from my post of october 29 and keeping the rule of mandatory defaults :

proc drawmle -namedargs {width {30} height {20 -height height:} color {blue -color bg}} {
#body }

If I want to enforce input of color argument at call time, I would rewrite the definition as :

proc drawmle -namedargs -noempty {width {30} height {20 -height height:} color {"" -color bg}} {
#body }

As in SQL, the "noempty" constraint naturally propagates to input, so with the preceding definition, the call :

drawme width "" height 60 color blue

will allso throw an error.

-jm

Hypnotoad

unread,
Oct 31, 2017, 8:17:20 AM10/31/17
to
JM,

With respect, the concept here was to add named parameters to Tcl. How the proc responds to what it was given is still the proc's job. What you are describing is a means to front load argument processing to every proc in Tcl. And bake in a lot more rules than was intended. And the problem with too many rules is that developers end up either having to circumvent them or go back to writing straight Tcl.

What you could do instead was:

proc jmproc {name args} {
set body [lindex $args end]
# add your rules to the body
set fullargs [jpproc_args {*}[lrange $args 0 end-1]]
set fullbody [jpproc_rules {*}[lrange $args 0 end-1]]
append fullbody \n $body
proc $name $fullargs $fullbody
}

And then any jmproc would get reformatted arguments based on your spec, and validation rules based on your spec. Where:
jmproc_args -> Generate the list of arguments based on the spec
jmproc_rules -> Generate a matching set of validation rules for the arguments based on the spec

Matthew Hiles

unread,
Nov 1, 2017, 11:31:31 AM11/1/17
to
I do not think this should be part of core. As an extension, sure. As an extension included with core, maybe. If it is included with core than it is given that will become the common, default way to use named parameters and I don't like how overloaded it makes the proc declaration feel.

Additionally, I do not like the use of the @ symbol and agree with the suggestion of a switch parameter for proc.

Matthew Hiles

unread,
Nov 1, 2017, 12:02:17 PM11/1/17
to
One more thing. I understand Hypnotoad's eagerness to get this accepted into core and claim his $20,0000 (https://github.com/flightaware/Tcl-bounties) but I really do not want something that doesn't quite fit with the rest of Tcl (IMHO) affecting something so fundamental as proc declaration.


I think the dictionary is a bit overkill. I'd like something more like

Regular:

proc positionalProc {arg1 arg2} {}

Named:

proc -namedargs namedProc {named1 named2} {}

and called (I'm 50/50 whether or not to keep the prefixed -)

namedProc -named1 value1 -named2 value2


and why not add a python-like ability to mix positional and named

proc -namedargs mixedProc {args named1 named2} {}

where args works just like with a regular proc.


Default values could work just like a regular proc

proc -namedargs namedWithDefaultsProc { {named1 default1} {named2 default2} } {}

We're already used to doing a bit of variable manipulation (upvar / global / et al) so setting up an alias or reassigning after declaration isn't a big deal.

sled...@gmail.com

unread,
Nov 1, 2017, 4:57:19 PM11/1/17
to
On Thursday, October 26, 2017 at 12:59:19 AM UTC-4, Georgios Petasis wrote:
George,

Still seems like a solution for which there is no patent need. Why can't what you have expressed as a need be managed using args?

Default name and values could be set in an array. One could then 'array set' whatever args are present, thereby over writing the values in the array.

What am I missing??? Seriously.

I don't see where the juice is anywhere worth the squeeze and would do no more than add a level of complexity that might make it somewhat more challenging to develop a stable tcl.

How about instead, the dev group focuses on a replacement for the current event management (window binding) scheme.

Keith Nash

unread,
Nov 2, 2017, 2:25:14 PM11/2/17
to
Hi Sean,

Here are some suggestions.

(1) Non-availability by default in Tcl 8.x

To activate the new facilities, a command such as
package require namedParameters
should be mandatory. This would ensure 100% compatibility with existing
code - even code that defines obscure names like "@proc" to mean something
else - and it would also give us the freedom to choose less obscure names
for the new commands.

In order to use the new facilities, existing code would obviously need
adaptation, and it would be no hardship to have to add a "package require".

The "package require" requirement could be dropped at the next major
revision, i.e. Tcl 9.0; at this point users will expect to have to adapt
their scripts to allow for altered facilities including possible naming
conflicts.

9.0 would also be a good time to merge the @proc and proc commands, etc, if
this outcome is desired.

(2) Naming of commands.

I would much prefer an alphabetical name for the new commands, perhaps
"procx" instead of "@proc". The new commands are just ordinary Tcl
commands, and therefore they do not merit an expansion of the customary
character set. I would prefer that Tcl code does not acquire anything that
looks like Perl sigils.

New commands could be named:
@proc -> procx
@method -> methodx
@args -> upargs
New Variable
@spec -> argsSpec (local variable inside a @proc or @method)

"The community is presently in a debate as to whether seperate commands are
the best approach, or modifying proc and oo::define::method to accept flags
is better."

If separate commands are not used, then @spec (or specArgs) should not be
defined in commands that do not use the new facilities. Then backward
compatibility is assured irrespective of the name of the variable.

(3) ${@spec}

For consistency with existing facilities for introspection, the spec could
be accessed not by ${@spec} but by [info spec], with an empty return if this
command is called from a standard proc or method, and an error return if the
call is made from an inappropriate context (i.e. neither a proc, @proc,
method or @method).

Best wishes,

Keith Nash.

Hypnotoad

unread,
Nov 2, 2017, 3:58:13 PM11/2/17
to
Keith,

Thank you very much for the suggestions! They all made a lot of sense, and I'm adapting
the tip to match. I'm finding that ditching the @spec variable is actually simplifying a
great number of things. For one I was having to constantly convince the interpreter to
ignore @spec when figuring out things like [info args]. Having a dedicated [info spec] or
[info namedargs] also solves the dilemma of how to report name arguments to [info defaults].
(Namely, one doesn't.)

Thank you,

--Sean "The Hypnotoad" Woods

walto...@gmail.com

unread,
Nov 8, 2017, 6:28:19 PM11/8/17
to
On Wednesday, October 25, 2017 at 10:21:00 AM UTC-5, Hypnotoad wrote:
> I am currently seeking input on an alternative to tip#451, tip#479.

The functionality is tempting. But -- Tcl's beauty is in its simplicity.

Plus, this is easily implemented in pure Tcl.
(Although I understand this solution doesn't come with a $20k FlightAware bounty)

proc abc {args} {
set defaults {
a 1
b 2
c 3
}
set args [dict merge $defaults [dict map {k v} $args {expr {[dict exists $defaults $k] ? $v : [continue]}}]]
dict with args {}

...
}

I'm sure you can even rename the proc command and make it look really nice.

sled...@gmail.com

unread,
Nov 9, 2017, 4:14:05 PM11/9/17
to
That was my point, exactly, in a previous reply. This tip is a solution looking for a problem...

Hypnotoad

unread,
Nov 18, 2017, 2:26:19 PM11/18/17
to
For trivial cases, yes, this is an answer in search of a problem. But this tip isn't designed to answer trivial cases. It is designed to answer really huge and nasty cases that arise when you have a function than needs on the order of a dozen arguments and you suddenly find yourself needing to add a thirteenth. Oh yes... and there are hundreds of calls to it spread over thousands of lines of code.

For Tk commands, they accept options. But options require a lot of infrastructure that is nested in C. For complex functions we need a lightweight (and processor efficient) form of option handling. And it needs to be accessible for pure-tcl functions. Thus this tip.

sled...@gmail.com

unread,
Nov 19, 2017, 10:02:29 AM11/19/17
to
This is really simple:
1. if anything other than 'proc' (ie. @proc or procx) then perforce, this is not compatible in any way with tcl. If this facility is to be implemented, then it seems more than reasonable to modify the current internal proc evaluation process to consider -named option.

2. IMHO the only benefit to named options over the intelligent use of args is in the built-in error handling of an instance in which an 'invalid' option is specified.

Relative to your comments, it is not clear to my why the use of option-value pairs in args, subsequently mapped to any array doesn't scale or provide for the simple addition of another option. This is a solution used within a business application that supports real-time communication with a variety of ACD\Predictive Dialer vendors who feel free to add optional parameters to their messaging sub-systems as they deem necessary.

walto...@gmail.com

unread,
Nov 21, 2017, 3:31:40 AM11/21/17
to
On Sunday, November 19, 2017 at 9:02:29 AM UTC-6, sled...@gmail.com wrote:
>it is not clear to me why

Did you not see the part about the $20k? ;)

https://github.com/flightaware/Tcl-bounties#a-first-class-high-performance-non-hackish-way-to-do-named-parameters

sled...@gmail.com

unread,
Nov 21, 2017, 2:28:00 PM11/21/17
to
I was being considerate...
Wonder if any one has taken the time to speak with John O. about this...He might have a little insight as to why this feature was not implemented at the time he formulated tcl.

Hypnotoad

unread,
Nov 21, 2017, 5:04:21 PM11/21/17
to
Part of the reason is that when Tcl was a twinkle in John's eye, it wasn't so much a large scale integration system. It was a hack for exercising C tests.

A quick review (because the conversation has gotten of topic... A BIT...)

The hack to the Tcl core no longer requires a separate command @proc. Instead a new implementation emerged from using the currently ignored ability to add a default value to args. With tip479, that default is interpreted as a dict which describes how non-positional args are to be converted to local variables.

The other alternative to Tip 479 revolve around changing proc itself to accept additional arguments, tk like options, and a raft of other ... um ... stylings... that render Tcl code utterly unrecognizable to either humans or the various tools that are available in the wild for analyzing Tcl code.

I will admit, Tip 479 make Tcl look like Lisp with curly braces, but structurally the code is the same.

--Sean "The Hypnotoad" Woods

sled...@gmail.com

unread,
Nov 21, 2017, 7:58:36 PM11/21/17
to
Not according to https://www.tcl.tk/about/history.html

On the contrary, it appears that this tip contradicts one of his documented "Overalll Goals" that relates to extensibility - he used the term 'natural'.

One of the other goals relates to its ability to work with other applications, to wit: " As a result, Tcl ended up being used in applications ranging from stock trading to scientific visualization to manufacturing automation."

The operational word here is "scale".

So, again IMHO, this is a solution looking for a problem...and a solution seemingly not consistent with his overarching goal of it being a natural extension, which in my mind would be an extension to the current form of "proc"; not a @anything or a "procx", "y" or "z".

rene

unread,
Nov 22, 2017, 2:32:23 AM11/22/17
to
Am Mittwoch, 22. November 2017 01:58:36 UTC+1 schrieb sled...@gmail.com:
> So, again IMHO, this is a solution looking for a problem...and a solution
> seemingly not consistent with his overarching goal of it being a natural
> extension, which in my mind would be an extension to the current form of
> "proc"; not a @anything or a "procx", "y" or "z".

A real problem would be to support quadcode generation.
It would be nice to merge this approach with the use of annotations for quadcode generation.

Just my 0.02c

Rene

Hypnotoad

unread,
Nov 24, 2017, 8:08:15 AM11/24/17
to
With respect, I don't need a citation to the history of Tcl Tk. I've been hacking the core since before we had a bytecode engine. (Ok, ok, 8.0 alpha was out then, and I had a copy of Brent's second edition to work with a preview of the API. But when I started coding, 7.6 was still the stable release.)

With respect, you also have ignored my reply that stated for the core implementation, we don't actually use the @proc/procx as more than sugar. The real magic is in overloading the default field for "args".

And with utmost respect, Dr. Ousterhout is still alive and perfectly capable of speaking for himself. And he was part of the formation of the Tcl Core team, and very much a proponent of the idea that that group continue to develop Tcl in whatever direction they decided to take.

This particular idea (tip 479) in the end may not be fit for purpose. But the TIP process very much is working as intended. The TIP process has extended the language and it's capabilities immensely since its the Core Team's founding. So you can take the entire concept of Tcl being some sort of "originalist" masterpiece and redirect it to /dev/null for as much as I'm concerned.

With respect, of course.

--Sean "The Hypnotoad" Woods

Donal K. Fellows

unread,
Nov 26, 2017, 3:17:44 PM11/26/17
to
On 22/11/2017 07:32, rene wrote:
> A real problem would be to support quadcode generation.

If virtually all the implementation can always be in a C function
(exposed via any stub table) that we can call, the quadcode
implementation won't be too awful. It's needing to reimplement functions
that already exist within Tcl but which aren't exposed in the API that
is really annoying...

Donal.
--
Donal Fellows — Tcl user, Tcl maintainer, TIP editor.

rene

unread,
Nov 27, 2017, 5:56:19 AM11/27/17
to
Am Sonntag, 26. November 2017 21:17:44 UTC+1 schrieb Donal K. Fellows:
> On 22/11/2017 07:32, rene wrote:
> > A real problem would be to support quadcode generation.
>
> If virtually all the implementation can always be in a C function
> (exposed via any stub table) that we can call, the quadcode
> implementation won't be too awful. It's needing to reimplement functions
> that already exist within Tcl but which aren't exposed in the API that
> is really annoying...
>
Glad to hear.

n.b. nice sunset photo :)

Rene
0 new messages