Tcl Source Code

View Ticket
Login
Ticket UUID: 420507
Title: Inconsistent behaviour of [unknown]
Type: Bug Version: None
Submitter: msofer Created on: 2001-05-01 18:03:56
Subsystem: 45. Parsing and Eval Assigned To: msofer
Priority: 7 High Severity:
Status: Closed Last Modified: 2004-09-22 09:39:51
Resolution: Fixed Closed By: msofer
    Closed on: 2001-05-07 01:02:20
Description:
There is an inconsistency in the handling of [unknown]:
the bytecode engine always calls the global [unknown],
the direct eval engine calls [unknown] in the local
namespace. The following illustrates the bug:

% info patchlevel
8.4a2
% namespace eval mig {set l aaa}
aaa
% proc unknown args {puts global}
% proc mig::unknown args {puts local}
% namespace eval mig {$l}
global
% namespace eval mig {eval $l}
local

It is quite straightforward to patch the source to
obtain a consistent behaviour. The patch will be either
in generic/tclExecute.c (to get the bytecode compiler
to call the namespace [unknown]), or else in
generic/tclParse.c.

I do not know which of the two behaviours is the
correct one! The man page for 'unknown' does not
resolve the issue. OTOH, the behaviour was consistent
in 8.0.5 (always call [::unknown]):

% info patchlevel
8.0.5
% namespace eval mig {set l aaa}
aaa
% proc unknown args {puts global}
% proc mig::unknown args {puts local}
%  namespace eval mig {$l}
global
% namespace eval mig {eval $l}
global

I have not tested other versions.
User Comments: coldstore added on 2004-09-22 09:39:51:
Logged In: YES 
user_id=19214

For what it's worth, it seems to me that this inconsistency
was resolved in the least useful way.

Overriding unknown in a namespace would be a useful
facility, qv TIP 181

msofer added on 2001-05-04 04:18:24:
Logged In: YES 
user_id=148712

Patch registered as #421166 and committed.

hobbs added on 2001-05-04 03:29:10:
Logged In: YES 
user_id=72656

The patch from Miguel restores the unknown call to always 
ensure ::unknown, which seems correct.  Unless you want to 
be able to override unknown in a namespace, but that isn't 
defined anywhere, nor does it work currently (as the 
examples below show).  I recommend applying the patch from 
Miguel as is.  That also makes things consistent with the 
actual unknown docs (which make no allowance for any other 
unknown but the global one).

msofer added on 2001-05-04 00:47:04:
Logged In: YES 
user_id=148712

Clarification: 
* the bug is exposed since 8.1, exposed by
    proc unknown args {puts global}
    namespace eval mig {
        proc unknown args {puts local}
    }
    namespace eval mig aaa ;        #  global
    namespace eval mig aaa bbb;   #  local
    namespace eval mig {aaa bbb}; # global

* the modifications that created the "pure lists"
optimisation for eval (8.3) led to a further exposure of the
bug. The original script only shows this second exposure.

dgp added on 2001-05-03 21:46:15:
Logged In: YES 
user_id=80530

I assure you, Miguel, the behavior change takes
place between 8.2.3 and 8.3b1.  Regardez:

$ cat un.tcl
puts [info patchlevel]
namespace eval mig {set l aaa}
proc unknown args {puts global}
proc mig::unknown args {puts local}
namespace eval mig {$l}
namespace eval mig {eval $l}
namespace eval mig [list eval aaa]
namespace eval mig [list aaa]
namespace eval mig eval aaa
namespace eval mig aaa

$ /usr/local/src/tcl8.2.3/unix/tclsh un.tcl
8.2.3
global
global
global
global
global
global
$ /usr/local/src/tcl8.3b1/unix/tclsh un.tcl
8.3b1
global
local
local
global
local
global

Have you identified what change in that time frame
caused this bug?

msofer added on 2001-05-03 21:36:41:
Logged In: YES 
user_id=148712

Correction: the bug is exposed to tcl scripts ever since it
was created in 8.1 - namespace eval does a direct evaluation
only if it has multiple arguments. Therefore we should get
in 8.1 (for the same definitions of unknown as in the
original comment):

% namespace eval mig aaa
global
% namespace eval mig aaa bbb
local
% namespace eval mig {aaa bbb}
global

msofer added on 2001-05-03 06:28:18:

File Added - 5939: DIFF

Logged In: YES 
user_id=148712

The enclosed patch "DIFF" restores the behaviour of 8.0,
i.e., always call the global [unknown].

msofer added on 2001-05-02 23:06:22:
Logged In: YES 
user_id=148712

As far as I can tell:

(a) The bytecode engine has called the global [unknown] ever
since 8.0 (see {generic/tclExecute.c: TclExecuteByteCode,
INST_INVOKE} and {generic/tclBasic.c TclObjInvoke}

(b) The inconsistency was introduced in 8.1, with the parser
rewrite and the possibility of direct interpretation: the
new procedure Tcl_EvalObjv calls the namespace [unknown],
not the global one

(c) The inconsistency was exposed to scripts in 8.3, with
the "pure list optimisation" that allows a direct evaluation

dgp added on 2001-05-02 03:25:45:
Logged In: YES 
user_id=80530

The change in behavior occurred between Tcl
releases 8.2.3 and 8.3b1.  Using diffs, the
ChangeLog, and 'cvs annotate', determine what
code changes created the changed behavior,
and who made them.  Find out from them whether
this was an intended effect (I doubt it).

Unless they say yes, I think the change in
behavior within the 8.x releases was a bug,
and the 8.0 behavior should be restored.

Attachments: