Tcl Source Code

View Ticket
Login
Ticket UUID: f14b33ec9f900721ce156147ebd418ff7b930117
Title: changed behaviour wrt command names, namespaces and resolution
Type: Bug Version: 9.0
Submitter: emiliano Created on: 2024-09-05 23:59:16
Subsystem: 21. [namespace] Assigned To: nobody
Priority: 5 Medium Severity: Minor
Status: Open Last Modified: 2024-09-18 21:46:49
Resolution: None Closed By: nobody
    Closed on:
Description:
In Tcl up to 8.6 creating a command with a leading single colon is forbidden in all namespaces except the root {} namespace:

$ tclsh8.6 
% namespace eval foo {proc :bar {} {puts hi}}
can't create procedure ":bar" in non-global namespace with name starting with ":"

This makes sense since such command is unreachable using its fully qualified name. ::foo:::bar resolves to the 'bar' command in the 'foo' namespace, given the rule that 'two or more colons' are namespace separators.

With Tcl 9, however, it's possible to create such command, but it can't be reached using its full qualified name:

$ tclsh9.0 
% namespace eval foo {proc :bar {} {puts hi}}
% namespace eval foo {namespace which :bar}
::foo:::bar
% ::foo:::bar
invalid command name "::foo:::bar"

This change will undoubtely affect a lot of Tk applications since it's common practice to use [namespace which] to fully qualify bindings and other callbacks.

Tcllib will be affected too, for example math::calculus uses [namespace which] to fully qualify procs used as functions.
User Comments: emiliano added on 2024-09-18 21:46:49:
There's already name constraints:

* Names can't contain the namespace separator
* Namespace names can't be the empty string.

wrt [dict with], there's already several ways it can fail to create the variables:

* The dict contains a key which is the same as the dict variable.

% set foo {foo 1 bar 2}; dict with foo {}
missing value to go with key

* The dict contains a key which maps to an already existing array.

% array set bar {} ; set foo {bar 1 baz 2} ; dict with foo {}
can't set "bar": variable is array

* A key resolves to a namespace which doesn't exists.

% set foo {baz::grill 2} ; dict with foo {}
can't set "baz::grill": parent namespace doesn't exist

The morale is: don't use [dict with] if you don't control the keys.

pooryorick added on 2024-09-14 08:42:14:

An example for consideration: dict with creates a variable for each key and gives it the name of the key. It's useful not to encounter errors when creating these variables. There are various similar examples. It's a good idea to be careful about prohibiting things unless there really is a compelling reason. Tcl is not a bondage-and-discipline language.


pooryorick added on 2024-09-14 08:35:14:

Names that have ambiguous absolute names can be considered private, and this is useful. Those who don't want the hassle of such names can simply avoid using them to name things. There's no compelling reason to prohibit any names.


pooryorick added on 2024-09-14 07:19:39:

In my opinion the proper principle for names (variable, procedure, and namespace) is that no names should be forbidden in any namespace, and that any issues should be resolved in the direction of making this true for Tcl.


oehhar added on 2024-09-09 09:44:04:

As it is still working as in 8.6, I revert my requirement to list it in the migration hints.

I was wrong with the documentation change. It is still on the namespaces.n page (I suppose) and the text is still the same:

There are a few remaining points about qualified names that we should cover. Namespaces have nonempty names except for the global namespace. :: is disallowed in simple command, variable, and namespace names except as a namespace separator. Extra colons in any separator part of a qualified name are ignored; i.e. two or more colons are treated as a namespace separator. A trailing :: in a qualified variable or command name refers to the variable or command named {}. However, a trailing :: in a qualified namespace name is ignored.

I would consider it as a bug, that namespaces may start with ":" in 9.0. Those namespaces may never be accessed using the colon syntax.

Thank you, Harald


oehhar added on 2024-09-09 09:33:34:

As this change is apparently intentional, it should be mentioned in the migration notes:

https://core.tcl-lang.org/tcl/wiki?name=Migrating+scripts+to+Tcl+9&p, probably chapter "Change in variable name resolution".

I always thouht it personally useful, that namespaces could be constructed by concatenation. Due to that, "::::" was allowed.

And it still works (TCL 9.0b3):

% namespace eval ::n1 {variable v1 v1}
% set ::n1::v1
v1
% set ::::n1::v1
v1
% set :::n1::v1
v1
% set :::n1::::v1
v1
% set :::n1:::v1
v1
% proc ::n1::p1 {} {puts p1}
% ::n1::p1
p1
% :::n1::p1
p1
% :::n1:::p1
p1
% n1::p1
p1
% n1:p1
invalid command name "n1:p1"

Quite interesting....

Thank you for all, Harald


oehhar added on 2024-09-09 08:44:15:

Thanks for the great finding.

TCL 8.6 documentation says:

Extra colons in any separator part of a qualified name are ignored; i.e. two or more colons are treated as a namespace separator.

This phrase is not present in TCL 9.0 documentation.

The TTT meeting today proposed to list that as known bugs in 9.0.0 and not delay 9.0.0 for this bug. It is proposed to address this with 9.0.1.

Harald