Tcl Source Code

View Ticket
Login
Ticket UUID: 781929
Title: [lexpand] expand-in-place command
Type: Patch Version: None
Submitter: muonics Created on: 2003-08-02 11:32:36
Subsystem: 45. Parsing and Eval Assigned To: msofer
Priority: 3 Low Severity:
Status: Closed Last Modified: 2003-10-03 19:17:23
Resolution: Rejected Closed By: dkf
    Closed on: 2003-10-03 12:17:23
Description:
This relatively simple patch to Tcl 8.4.4 adds a new
"lexpand" command to the core for expanding lists "in
place" during evaluation.  It is suggested as an
alternative to the proposed {} prefix syntax convention
described by TIP #144.  "lexpand" was chosen instead of
"expand" because Unix systems tend to have an "expand"
command, which might be more likely to cause
silent-but-erroneous behavior runing scripts using the
new command in older versions of Tcl (this way it's
more likely to give an "unknown command" error than do
something incorrect with the arguments).  Usage:

lexpand ?list ...?

The patch adds a new Tcl_Obj type that is just a
renamed list object for purposes of flagging the object
as requiring expansion. The command takes zero or more
arguments and returns a list object consisting of those
arguments but with the new object type.

TclEvalObjvInternal() is modified to recognize this
type and reconstruct the objv array, expanding any
elements of the new type into separate arguments before
looking up and calling the command.

lexpand accepts multiple arguments so that it can be
nested for multiple levels of expansion.  e.g.

command [lexpand [lexpand $args]]

It can also be used to execute list variables directly
(similar to eval):

[expand $script]

It cannot, of course, be used with "set" unless the
expansion results in a single element result:

set x [list a b c d e]
set y [expand $x]

...will result in an error because it is equivalent to...

set y a b c d e

Likewise, you cannot return [expand $list], unless
$list matches the allowed options, return codes, etc.
for return.  In other words, I guess you could say that
the new Tcl_Obj type is not a first-class object, which
is essentially the intent of expansion in place.

One caveat: no assumption is made in this version of
the patch as to whether empty list elements should be
discarded.  That is...

[expand $script]

..is not the same as...

eval $script

... if $script contains empty strings or lists.  e.g.

set script [list puts ""]
[expand $script]  =>  puts ""
eval $script => puts

However, it could be with very minor changes (just
build the result element-by-element in
Tcl_LexpandObjCmd() rather than calling
Tcl_NewListObj() with the full set of arguments). 
Perhaps the behavior could be made an option.  But I
wasn't certain which behavior people expect/desire.

My hope is that this will make the {} syntax
unnecessary, but I believe that it would be extremely
easy to support both forms if desired or use this code
as the basis for {} if (unfortunately) that syntax is
chosen over [lexpand].

Oh, and please check to make sure there aren't any
reference counting issues! :)
User Comments: dkf added on 2003-10-03 19:17:23:
Logged In: YES 
user_id=79902

Closing this as invalid because there was a large consensus
(in KBK's poll on tcl-core) that the [lexpand] approach to
this problem was not the right way to do it.

muonics added on 2003-08-10 03:18:40:

File Added - 58284: lexpandv2.diff

Logged In: YES 
user_id=498198

lexpandv2.diff replaces lexpand.diff, correcting problems
handling multiple arguments (due to an incomplete merge from
my 8.4.3 original to 8.4.4) and with handling of various
invocations involving empty lists that could crash due to
Tcl's creating empty list objects as string objects instead.
 ie., the following test cases are fixed:

cmd [lexpand]
cmd [lexpand [list]]
[lexpand]
[lexpand [list]]
[lexpand [list [list]]]
cmd [lexpand a b c d e]

This does not address full BCC compatibility yet.

msofer added on 2003-08-08 22:11:00:
Logged In: YES 
user_id=148712

The only point which is relevant here is: this is not a Tcl
command in the current sense, it implies a syntax change. 
Whether that is good or bad, better or worse than other
alternatives should be discussed elsewhere.
Sorry, I started the discussion in these terms, didn't I? My
bad: TCLCORE, chat and wiki is already too many places ...

The problem with the [set] example is that
   set x [whatever arg1 $argVal ...]
would never raise a "too many args" error in [set], *except*
if "whatever" happens to be "lexpand". This illustrates
nicely that [lexpand] does not behave like a Tcl command.
Note that you cannot write a proc or a C-command that raises
that error. 

Adopting this patch implies modifying the Endekalogue, hence
its approval requires a TIP. Therefore, I will wait till the
dust settles to evaluate the patch - I can't do that
properly know, as the decision as to what is acceptable is
not in my hands. An evaluation today would have to be
"rejected, violates Tcl's syntax".

Fair enough?

muonics added on 2003-08-08 21:27:51:
Logged In: YES 
user_id=498198

> Making that example work within the current syntax would
> require [set] to expand its arguments, thus causing errors
> in thing like
>     set x [list 1 2 3]
> Alternatively, [set] would need to know more about how each
> word argument was generated (is it the resut of an
> [lexpand]?)

But it is by design that "set x [lexpand ...]" will cause an
error.  Do you expect if TIP #144's syntax is adopted that
any of these will succeed?

set x {}[...]
set x {}$y

How about these, under current circumstances?

eval set x [...]
eval set x $y

I very much doubt it!  What do these all have in common?  In
every case you're telling Tcl to expand either the value of
y or the result of [...] into multiple arguments before
passing them to the set command.  All four of the above
behave exactly the same (modulo needing to fix the bytecode
issue) as:

set x [lexpand [...]]
set x [lexpand $y]

(As for whether you want to say that alters Tcl's syntax, or
as I see it that it alters the substitution rules a little
but does not introduce new syntax, is largely matter of
semantics.  I do not see it as altering the syntax because
the parser remains unchanged, unlike the {} prefix proposal.
 [lexpand] is just [list] with a different object type, so
it *is* just a command; it's just that this new object type
is treated specially during evaluation.  Whether {} prefix
or [lexpand] is adopted, however, either way the Endekalogue
will have to be updated, so that's not in its self a logical
reason to choose one over the other.)

I think it would be a really bad idea for *either* the {}
prefix or the [lexpand] command to cause that set to
succeed, because that would amount to *two* changes to the
Endekalogue, or at least inconsistent behavior: "if ... is
used, the value is expanded into multiple arguments before
passing to the command.  oh, unless that command is set." 
Why would you want that, especially when that's not the
behavior expected of eval set ...?

msofer added on 2003-08-08 20:40:57:
Logged In: YES 
user_id=148712

This discussion is being actively pursued in other forums,
but I'll register my caveats here for the record and defer
any resolution until the syntax discussion is settled.
It is definitely not true that this command does not alter
Tcl's syntax; it does, and IMHO in a very perverse manner.
This is shown by the author's remark that
   set y [lexpand $x]
results in an error, a violation of rules 6, 10 and/or 11 in
the endekalogue, which mandate that the resultof a [..]
substitution is a single word and that substitution is
single-pass.
Making that example work within the current syntax would
require [set] to expand its arguments, thus causing errors
in thing like
    set x [list 1 2 3]
Alternatively, [set] would need to know more about how each
word argument was generated (is it the resut of an
[lexpand]?) to treat it accordingly; this violates rule 2.
Or else there is a second substitution pass just for the
results of [lexpand], violating rule 10

In any case, this proposal does introduce new syntax;
[lexpand] is not a Tcl command in the usual sense.

muonics added on 2003-08-07 17:26:00:
Logged In: YES 
user_id=498198

This appears to just be due to the fact that certain core
bytecode compiled commands don't go through
TclEvalObjvInternal() when executed.  Probably not difficult
to fix (at least not significantly different than what would
need to be done for the {} prefix to work).  I'll look into
it soon, though I'm not sure the TCT is even considering it
(don't see anything on the list - just new-syntax versus
eval-like-replacement a la TIP#103, where this is neither.).

jenglish added on 2003-08-07 07:31:16:
Logged In: YES 
user_id=68433

This works fine when invoked at top-level:

% set l [list x y z] 
% set x [list a b c [lexpand $l] d e f]
==> a b c x y z d e f

but not inside a proc:

proc test {} {
    set l [list x y z] 
    set x [list a b c [lexpand $l] d e f]
    return $x
}
test
==> a b c {{x y z}} d e f

muonics added on 2003-08-02 19:00:52:
Logged In: YES 
user_id=498198

Oops!  My caveat is wrong.  These are actually equivalent
after all:

[expand $script]
eval $script

muonics added on 2003-08-02 18:32:36:

File Added - 57623: lexpand.diffs

Attachments: