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

Feature request: 'apply' command

8 views
Skip to first unread message

Joe English

unread,
Jan 26, 1997, 3:00:00 AM1/26/97
to

I think a command like "apply command $argList",
which simply invokes 'command' with the arguments
'$argList', would be a useful addition to Tcl 8.0.

This command could be used in place of 'eval' in
many if not most cases, and would be much more efficient,
especially under Tcl 8.0, since it would not need to
invoke the statement parser and byte-code compiler.


I'd also like to see similar functionality in
the C API, something like:

Tcl_CallCommand(Tcl_Interp *, char *cmdName, int argc, char **argv);
Tcl_CallObjCommand(Tcl_Interp *, char *, int, Tcl_Object **);

and while I'm at it, a C interface to the 'subst' command
would be really nice too...


--Joe English

jeng...@crl.com

Michael Schumacher

unread,
Jan 27, 1997, 3:00:00 AM1/27/97
to

Joe English <jeng...@crl.com> wrote:

: I think a command like "apply command $argList",


: which simply invokes 'command' with the arguments
: '$argList', would be a useful addition to Tcl 8.0.

: This command could be used in place of 'eval' in
: many if not most cases, and would be much more efficient,
: especially under Tcl 8.0, since it would not need to
: invoke the statement parser and byte-code compiler.

Would you mind explaining exactly _what_ makes "apply" different from
"eval" and why it would be more efficient? I can't see why it wouldn't
need being parsed and compiled.

[...]

: and while I'm at it, a C interface to the 'subst' command


: would be really nice too...

Is Tcl_SubstCmd() too "highlevel" for your needs?


mike

Hume Smith

unread,
Jan 27, 1997, 3:00:00 AM1/27/97
to

In article <85437995...@htc01.hightec.saarlink.de> mi...@hightec.saarlink.de (Michael Schumacher) writes:

> Joe English <jeng...@crl.com> wrote:
>
> : I think a command like "apply command $argList",
> : which simply invokes 'command' with the arguments
> : '$argList', would be a useful addition to Tcl 8.0.
>
> : This command could be used in place of 'eval' in
> : many if not most cases, and would be much more efficient,
> : especially under Tcl 8.0, since it would not need to
> : invoke the statement parser and byte-code compiler.
>
> Would you mind explaining exactly _what_ makes "apply" different from
> "eval" and why it would be more efficient? I can't see why it wouldn't
> need being parsed and compiled.

have you forgotten that eval parses and evaluates $ and [ *again* (like expr)?
look to see what this does:
set x hello
set f {$x}
eval puts $f
the majority of my use of eval doesn't *want* that second evaluation; i'm
going to a lot of trouble to prevent it. i always have lingering worry that
there's an unguarded $ or [ floating around, especially in any arguments i
can't put in list:
eval foo [list $arg1 $arg2 $arg3] $argrest
i know $arg1 $arg2 and $arg3 will be delivered to foo as they are, but
i'm always wondering whether $argrest has been built right.

--
Hume Smith <URL:mailto:hcls...@tallships.istar.ca>
<URL:http://dess.tallships.istar.ca/%7Ehclsmith/>

Hume Smith

unread,
Jan 27, 1997, 3:00:00 AM1/27/97
to

i suppose i should remember that the tcl analogue to Lisp's
(apply cmd arg1 arg2 arg3 nil)
is
$cmd $arg1 $arg2 $arg3
tcl being nice enough to treat arg0 no differently from the others...
so i'd say what we're looking for is a way to spread list-valued arguments:
(apply cmd arg1 argrest)
does *not* rewrite as
$cmd $arg1 $argrest
nor even as
eval [list $cmd $arg1] $argrest
unless argrest has been constructed carefully.

Joe English

unread,
Jan 27, 1997, 3:00:00 AM1/27/97
to

On Sun Jan 26 1997 I wrote:

>
>I think a command like "apply command $argList",
>which simply invokes 'command' with the arguments
>'$argList', would be a useful addition to Tcl 8.0.


I'm sorry, that was terribly rude of me :-)

What I *meant* to say was, "If I were to implement these
features and write man pages for them, would there
be any interest in adding them to Tcl 8.0?"


[ P.S. If so, please reply via e-mail as well; CRL's newsfeed
has been really flaky lately, I don't think we're getting
*any* postings from Sun ...
]


>This command could be used in place of 'eval' in
>many if not most cases, and would be much more efficient,
>especially under Tcl 8.0, since it would not need to
>invoke the statement parser and byte-code compiler.
>
>

>I'd also like to see similar functionality in
>the C API, something like:
>
> Tcl_CallCommand(Tcl_Interp *, char *cmdName, int argc, char **argv);
> Tcl_CallObjCommand(Tcl_Interp *, char *, int, Tcl_Object **);
>

>and while I'm at it, a C interface to the 'subst' command
>would be really nice too...
>
>

>--Joe English
>
> jeng...@crl.com


John Ousterhout

unread,
Jan 28, 1997, 3:00:00 AM1/28/97
to

In article <5cjec5$g...@crl2.crl.com>, jeng...@crl.com (Joe English) writes:
|> What I *meant* to say was, "If I were to implement these
|> features and write man pages for them, would there
|> be any interest in adding them to Tcl 8.0?"

Probably not... we just have too many other things to worry about.
Besides, I'm not sure that "apply command $argList" is a huge
improvement over the following equivalent code:

set result {}
foreach i $argList {
lappend result [command $i]
}

In fact, couldn't you just define the "apply" command as a procedure that
uses "uplevel"?

Hume Smith

unread,
Jan 28, 1997, 3:00:00 AM1/28/97
to

In article <5clbed$6...@engnews2.Eng.Sun.COM> ous...@tcl.eng.sun.com (John Ousterhout) writes:

> Besides, I'm not sure that "apply command $argList" is a huge
> improvement over the following equivalent code:

> set result {}
> foreach i $argList {
> lappend result [command $i]
> }

uh, sorry mr O, that's map, not apply. i think mr English was wishing for
something like lisp's apply and funcall:

> I think a command like "apply command $argList",
> which simply invokes 'command' with the arguments
> '$argList', would be a useful addition to Tcl 8.0.

> This command could be used in place of 'eval' in
> many if not most cases, and would be much more efficient,
> especially under Tcl 8.0, since it would not need to
> invoke the statement parser and byte-code compiler.

i know i was. actually, (funcall arg0 arg1 arg2) already translates nicely
to tcl: $arg0 $arg1 $arg2 it's the list argument that apply takes that gets
us into eval messes. i wouldn't mind an apply that took lists in all its
arguments; i could stand to run a few list commands as long as i didn't have
to worry about another set of $ and [ substitutions. (\ would still be needed,
i bet.)

Joe English

unread,
Jan 28, 1997, 3:00:00 AM1/28/97
to

John Ousterhout <ous...@tcl.eng.sun.com> wrote:
>jeng...@crl.com (Joe English) writes:
>|> What I *meant* to say was, "If I were to implement these
>|> features and write man pages for them, would there
>|> be any interest in adding them to Tcl 8.0?"
>
>Probably not... we just have too many other things to worry about.
>Besides, I'm not sure that "apply command $argList" is a huge
>improvement over the following equivalent code:
>
> set result {}
> foreach i $argList {
> lappend result [command $i]
> }


That's something different than what I had in mind
(although that would also be a useful construct).
What I was thinking of was something like Scheme's
'apply' function. It could be implemented in Tcl
like this:

proc apply {command argList} {
set args [protectSpecialChars $argList]
return [eval $command $args]
}

given a suitable definition of 'protectSpecialChars',
(which would replace $ with \$, [ with \[, etc., in the
appropriate places, to prevent 'eval' from doing any
unintended variable or command substitution).

The advantage of having this as a built-in procedure
would be that 'apply cmdName $argList' wouldn't need
to concatenate "cmdName $argList" into a single string,
parse and compile the string to bytecode, then execute
the bytecode (like "eval command $argList" currently does),
and there would be no need to protect []{}\$ characters.
Instead, it could simply split $argList into list elements
(and in many cases, the argument list parameter will
already be stored as a Tcl_ListObj), look up the Tcl_CmdInfo
for 'cmdName', and call the objProc.


'apply cmdName $argList', if 'apply' were a Tcl primitive,
would be safer than 'eval cmdName $argList', and *much*
more efficient than 'eval cmdName [protectSpecials $argList]'.

--Joe English

jeng...@crl.com

Grant Reaber

unread,
Jan 28, 1997, 3:00:00 AM1/28/97
to

In article <5clbed$6...@engnews2.Eng.Sun.COM>,
John Ousterhout <ous...@tcl.eng.sun.com> wrote:

>In article <5cjec5$g...@crl2.crl.com>, jeng...@crl.com (Joe English) writes:
>|> What I *meant* to say was, "If I were to implement these
>|> features and write man pages for them, would there
>|> be any interest in adding them to Tcl 8.0?"
>
>Probably not... we just have too many other things to worry about.
>Besides, I'm not sure that "apply command $argList" is a huge
>improvement over the following equivalent code:
>
> set result {}
> foreach i $argList {
> lappend result [command $i]
> }
>
>In fact, couldn't you just define the "apply" command as a procedure that
>uses "uplevel"?

I think you're thinking of "map", not "apply". "Apply" is a different
idea from lisp, which applies a command to a list of arguments, something
like a limited version of Tcl's eval . I think Mr. English suspects
there could be a speed advantage to "apply" since it wouldn't have to
look at string representations. I don't know if that is true or not.
I'm concerned about the security implications of eval. Suppose I want
to invoke a command that takes a variable number of arguments with some
arguments that have been supplied by an untrusted source. Apply would
do what I want (in particular, it would signal an error if the second
argument wasn't a list). With eval, I could be bitten. For instance,

set x {[puts gotcha]}
eval puts $x
>gotcha
>

With apply, this couldn't happen. I recently faced this problem while
designing an internet server.

Here is an implementation of apply for lists of three elements or less.
It might be nice if the invokation could be done in the context of
the caller.

proc apply {cmd list} {
switch [llength $list] {
0 {$cmd}
1 {$cmd [lindex $list 0]}
2 {$cmd [lindex $list 0] [lindex $list 1]}
3 {$cmd [lindex $list 0] [lindex $list 1] [lindex $list 2]}
}
}

This is another idea, but I'm not sure if it's equivalent.

proc apply {cmd list} {
uplevel [linsert $list 0 $cmd]
}

Anyway, there's still the speed issue.

Grant


Jay A. Carlson

unread,
Jan 29, 1997, 3:00:00 AM1/29/97
to

In article <5cgeal$t...@crl13.crl.com>, Joe English <jeng...@crl.com> wrote:

> I think a command like "apply command $argList",
> which simply invokes 'command' with the arguments
> '$argList', would be a useful addition to Tcl 8.0.

This is one of my pet peeves in Tcl. I've started writing this at
least three times on my own.

> This command could be used in place of 'eval' in
> many if not most cases, and would be much more efficient,
> especially under Tcl 8.0, since it would not need to
> invoke the statement parser and byte-code compiler.

I don't care about efficiency so much as reliability. Here's an
example of something I've worked around repeatedly:

I have a procedure that opens an xterm. Users suggest that I give
them the ability to optionally set the title and icon name of the
xterm. So I pull up emacs and start writing:

proc openXterm {{title ""} {iconname ""}} {
set command "xterm -bg Blue -fg White"
if {$title != ""} {
append command " -T $title"
}
if {$iconname != ""} {
append command " -n $iconname"
}
eval "exec $command &"
}

...and after this ships, I start getting support phone calls because
the poor users wanted to have spaces in the window title, and eval of
course treats everything after the space as another argument, and
xterm loses badly. So then I start playing with things like

append command " -n \"$iconname\""

and list operations postprocessed by really hairy string ops. :-( In an
attempt to avoid a repeat of the previous experience with spaces, I
stare at Tcl's quoting rules and figure out what I can do to get
*everything*, especially braces and dollar signs, fixed up in such a way
they end up as properly quoted literals in an eval.

I've seen a lot of Tcl code out there that *doesn't* handle these
issues. The Tcl Frequently-Made-Mistakes doc suggests eval as a way
out of apply-like problems, without any caveats.

BTW, you won't win any points by suggesting

exec /bin/sh -c $command &

because that just punts all those quoting problems into the shell.

Anyway, what I *wanted* to write in the first place was:

proc openXterm {{title ""} {iconname ""}} {
set cmdargv [list xterm -bg Blue -fg White]
if {$title != ""} {
lappend cmdargv "-T" $title
}
if {$iconname != ""} {
lappend cmdargv "-n" $iconname
}
lappend cmdargv "&"

apply exec $cmdargv
}

which should cleanly handle anything a user would stuff into $title.

...oops, I lied; passing in "|" as a title still blows up. But I
think the point of this example is clear, regardless of the quirks of
exec. apply is about being able to cleanly write dynamic code that
does not require the full generality and danger of eval.

> I'd also like to see similar functionality in
> the C API, something like:
>
> Tcl_CallCommand(Tcl_Interp *, char *cmdName, int argc, char **argv);
> Tcl_CallObjCommand(Tcl_Interp *, char *, int, Tcl_Object **);

When I made my first attempt at writing my apply extension, I was
surprised to see that these functions had not already been factored
out of the eval core.

P.S.: how *do* you pass "|" as a single argv to a process in Tcl?
--
Jay Carlson n...@kagoona.mitre.org n...@nop.com
The MITRE Corporation, Bedford MA

Flat text is just *never* what you want. ---stephen p spackman

Hume Smith

unread,
Jan 29, 1997, 3:00:00 AM1/29/97
to

In article <5cmcnj$p...@top.mitre.org> n...@slothrop1.mitre.org (Jay A. Carlson) writes:

> P.S.: how *do* you pass "|" as a single argv to a process in Tcl?

you don't, as yet.

Michael Schumacher

unread,
Jan 29, 1997, 3:00:00 AM1/29/97
to

Joe English <jeng...@crl.com> wrote:

: What I was thinking of was something like Scheme's


: 'apply' function. It could be implemented in Tcl
: like this:

: proc apply {command argList} {
: set args [protectSpecialChars $argList]
: return [eval $command $args]
: }

: given a suitable definition of 'protectSpecialChars',
: (which would replace $ with \$, [ with \[, etc., in the
: appropriate places, to prevent 'eval' from doing any
: unintended variable or command substitution).

I think that

proc apply {cmd argl} {
regsub -all . $argl {\\\0} pargl
return [eval $cmd $pargl]
}

should do the trick.


mike

Michael Schumacher

unread,
Jan 29, 1997, 3:00:00 AM1/29/97
to

Hume Smith <hcls...@tallships.istar.ca> wrote:

: In article <5cmcnj$p...@top.mitre.org> n...@slothrop1.mitre.org (Jay A. Carlson) writes:

: > P.S.: how *do* you pass "|" as a single argv to a process in Tcl?

: you don't, as yet.

Why not?

mike@phoenix:/home/mike > tclsh
% exec sh -c {echo \|}
|
%


mike

Norman Richards

unread,
Jan 29, 1997, 3:00:00 AM1/29/97
to

Joe English <jeng...@crl.com> wrote:
> What I was thinking of was something like Scheme's
> 'apply' function. It could be implemented in Tcl
> like this:
> proc apply {command argList} {
> set args [protectSpecialChars $argList]
> return [eval $command $args]
> }

I might be terribly dense, but the followings seems to work for me:

proc apply {command arglist} {
return [eval [concat [list $command] $arglist]]
}


______________________________________________________________________________
o...@cs.utexas.edu soli deo gloria

Hume Smith

unread,
Jan 29, 1997, 3:00:00 AM1/29/97
to

erruuhgh okay ... now port it to Windoze :)

Rodrigo Ventura (Yoda)

unread,
Jan 29, 1997, 3:00:00 AM1/29/97
to

Joe English wrote (27-Jan-97 23:39:49):

>On Sun Jan 26 1997 I wrote:

>>
>>I think a command like "apply command $argList",
>>which simply invokes 'command' with the arguments
>>'$argList', would be a useful addition to Tcl 8.0.

>I'm sorry, that was terribly rude of me :-)

>What I *meant* to say was, "If I were to implement these


>features and write man pages for them, would there
>be any interest in adding them to Tcl 8.0?"

>[ P.S. If so, please reply via e-mail as well; CRL's newsfeed
> has been really flaky lately, I don't think we're getting
> *any* postings from Sun ...
>]

Hi. I suppose that that feature already exists. Let me show you:

eval "command $argList"

I've done it and it worked. However, the reference to the name 'apply'
reminded me from LISP. In LIST there is some quite useful functions for
applying functions to lists. For instance, the 'mapcar' function applyes a
given function to each element of a given list, and returns a list of the
values returned by the calls. Wouldn't this be useful in Tcl? To do this
presently in Tcl you'll have to hack a bit:

proc mapcar {fun argList} {
set tmp {}
foreach $arg $argList {
lappend tmp [$fun $argList]
}
return $tmp
}


Regards,

--

*** Rodrigo Martins de Matos Ventura, alias <Yoda>
*** nu...@isr.ist.utl.pt, http://www.isr.ist.utl.pt/~nuron
*** Instituto Superior Tecnico, Lisboa, Portugal
*** PGP Public Key available on my homepage
*** Key fingerprint = 0C 0A 25 58 46 CF 14 99 CF 9C AF 9E 10 02 BB 2A


Michael Schumacher

unread,
Jan 29, 1997, 3:00:00 AM1/29/97
to

Hume Smith <hcls...@tallships.istar.ca> wrote:
: > : > P.S.: how *do* you pass "|" as a single argv to a process in Tcl?

: >
: > : you don't, as yet.
: >
: > Why not?
: >
: > mike@phoenix:/home/mike > tclsh
: > % exec sh -c {echo \|}
: > |
: > %

: erruuhgh okay ... now port it to Windoze :)

Been there, done that, got gnu-win32... ;^)


mike

Hume Smith

unread,
Jan 29, 1997, 3:00:00 AM1/29/97
to

In article <1666.6968...@isr.ist.utl.pt> nu...@isr.ist.utl.pt (Rodrigo Ventura (Yoda)) writes:

> From: nu...@isr.ist.utl.pt (Rodrigo Ventura (Yoda))
> Newsgroups: comp.lang.tcl
> Date: 29 Jan 97 12:07:27 +0000
> Organization: Instituto Superior Tecnico
>
> Joe English wrote (27-Jan-97 23:39:49):
> >On Sun Jan 26 1997 I wrote:
>
> >>
> >>I think a command like "apply command $argList",
> >>which simply invokes 'command' with the arguments
> >>'$argList', would be a useful addition to Tcl 8.0.
>
>
> >I'm sorry, that was terribly rude of me :-)
>
> >What I *meant* to say was, "If I were to implement these
> >features and write man pages for them, would there
> >be any interest in adding them to Tcl 8.0?"
>
>
> >[ P.S. If so, please reply via e-mail as well; CRL's newsfeed
> > has been really flaky lately, I don't think we're getting
> > *any* postings from Sun ...
> >]
>
> Hi. I suppose that that feature already exists. Let me show you:
>
> eval "command $argList"

D'OH! okay, i guess we need an actual example.

i recently kludged up a listbox lookalike using a canvas (using pure tcl;
i can vouch for the screaming need for better support for megawidgets).
i'd supply it with a procedure that rendered a row as i wanted and the
fancylist would do the vertical placement... anyway, fancylist would take the
elements of an insert and treat them as argument lists to this procedure, eg
.fl insert end {#f00 Red} {#0f0 Green} {#00f Blue}
while i realise it was incorrect in some sense, it was natural to write
something like
.fl insert end {$2.13 beans} {$1.11 carrots} {$.69 gum}
while testing. i had built fancylist to ignore whatever errors were
generated around the procedure, and i had the darndest time figuring why
the price list wasn't doing anything... it was because i'd had to write
something like
eval [list $proc] $args
to burst the argument list, and args was "$2.13 beans" or whathaveyou, which
of course made eval try to look up the variable named 2, which didn't exist!

i protected myself from that by doing something like this before the eval:
foreach i $args { lappend safer $i }
a nice way to spend one's time in an already rather slow process.

it would have been *very* nice in that situation to have a proper apply.

James Cribb

unread,
Jan 31, 1997, 3:00:00 AM1/31/97
to

Norman Richards (o...@cs.utexas.edu) wrote:
:
: proc apply {command arglist} {

: return [eval [concat [list $command] $arglist]]
: }

Almost, but

% llength {[puts boom]}
2
% apply llength {[puts boom]}
boom
0

Also, the "return" is redundant. How about this:

% proc apply {command arglist} {
eval [concat [list $command] [list $arglist]]
}
% apply llength {[puts boom]}
2

--
James Cribb (james...@aus.deuba.com)
Information Technology, Deutsche Morgan Grenfell Australia Limited
Phone: +61 2 9258 1375 Fax: +61 2 9258 1004
My opinions are not necessarily those of my employer. Pity.

Steve Ball

unread,
Feb 3, 1997, 3:00:00 AM2/3/97
to

In article m...@anubis.reed.edu, gre...@reed.edu (Grant Reaber) writes:
>I'm concerned about the security implications of eval. Suppose I want
>to invoke a command that takes a variable number of arguments with some
>arguments that have been supplied by an untrusted source. Apply would
>do what I want (in particular, it would signal an error if the second
>argument wasn't a list). With eval, I could be bitten. For instance,
>
>set x {[puts gotcha]}
>eval puts $x
>>gotcha
>>
>
>With apply, this couldn't happen. I recently faced this problem while
>designing an internet server.
>
>Here is an implementation of apply for lists of three elements or less.
>It might be nice if the invokation could be done in the context of
>the caller.
>
>proc apply {cmd list} {
> switch [llength $list] {
> 0 {$cmd}
> 1 {$cmd [lindex $list 0]}
> 2 {$cmd [lindex $list 0] [lindex $list 1]}
> 3 {$cmd [lindex $list 0] [lindex $list 1] [lindex $list 2]}
> }
>}

It turns out that eval is OK for this purpose, because it only performs
substitutions a fixed number of times. I had similar code to that above
in my Safe-Tk code (only I was handling fifty or more arguments so it was BIG!).

The code:

set untrusted {[puts gotcha]}
eval puts [list $untrusted]

is safe.

---
Steve Ball, Computer Science Dept., ANU Steve...@surfit.anu.edu.au
Ph. +61 6 2495146 http://surfit.anu.edu.au/steve/
Snail-mail: Canberra ACT 0200, AUSTRALIA
He's not the messiah, he's a very naughty boy!

--
Steve Ball, Computer Science Dept., ANU Steve...@surfit.anu.edu.au
Ph. +61 6 2495146 http://surfit.anu.edu.au/steve/
Snail-mail: Canberra ACT 0200, AUSTRALIA
He's not the messiah, he's a very naughty boy!

Hume Smith

unread,
Feb 4, 1997, 3:00:00 AM2/4/97
to

In article <5crncm$f...@plath.bain.oz.au> jam...@bain.oz.au (James Cribb) writes:

> the "return" is redundant. How about this:
>
> % proc apply {command arglist} {
> eval [concat [list $command] [list $arglist]]
> }
> % apply llength {[puts boom]}
> 2

that's wrong, it should be an error. and now the concat, list, and eval
are *all* redundant; this reduces exactly to
proc apply {c a} { $c $a }

Hume Smith

unread,
Feb 4, 1997, 3:00:00 AM2/4/97
to

In article <5crncm$f...@plath.bain.oz.au> jam...@bain.oz.au (James Cribb) writes:

> Also, the "return" is redundant. How about this:


>
> % proc apply {command arglist} {
> eval [concat [list $command] [list $arglist]]
> }
> % apply llength {[puts boom]}
> 2

that's wrong, it should be an error. also, concat, list, and eval are *all*
redundant in this; it reduces exactly to


proc apply {c a} { $c $a }

my idea of apply is that, lindex for lindex, apply list ... should be the
same as concat ...
proc apply {args} {
foreach i $args { foreach j $i { lappend l $j } }
eval $l
}

% apply llength {[puts boom]}

wrong # args: should be "llength list"
% apply list {[puts boom]}
{[puts} boom\]
% lindex [apply list {[puts boom]}] 0
[puts
% lindex [apply list {[puts boom]}] 1
boom]
% % set x [concat {$12} [info body apply]]
$12 foreach i $args { foreach j $i { lappend l $j } }
eval $l
% set y [apply list {$12} [info body apply]]
{$12} foreach i {$args} { foreach j $i { lappend l $j } } eval {$l}
% foreach i {0 1 2 3 4 5 6} {
puts -nonewline [string compare [lindex $x $i] [lindex $y $i]]
}
0000000%
% foreach i $x j $y {puts -nonewline [string compare $i $j]}
0000000%

Donal K. Fellows

unread,
Feb 4, 1997, 3:00:00 AM2/4/97
to

In article <5co9qg$3...@news.istar.ca>,
Hume Smith <hcls...@tallships.istar.ca> wrote:
> D'OH! okay, I guess we need an actual example.
>
> I recently kludged up a listbox lookalike using a canvas (using pure tcl;
> I can vouch for the screaming need for better support for megawidgets).
> I'd supply it with a procedure that rendered a row as I wanted and the
> fancylist would do the vertical placement... Anyway, fancylist would take the

> elements of an insert and treat them as argument lists to this procedure, eg
>
> .fl insert end {#f00 Red} {#0f0 Green} {#00f Blue}
>
> while I realise it was incorrect in some sense, it was natural to write

> something like
>
> .fl insert end {$2.13 beans} {$1.11 carrots} {$.69 gum}
>
> while testing. I had built fancylist to ignore whatever errors were
> generated around the procedure, and I had the darndest time figuring why
> the price list wasn't doing anything... It was because I'd had to write

> something like
>
> eval [list $proc] $args
>
> to burst the argument list, and args was "$2.13 beans" or whathaveyou, which
> of course made eval try to look up the variable named 2, which didn't exist!
>
> I protected myself from that by doing something like this before the eval:

>
> foreach i $args { lappend safer $i }
>
> a nice way to spend one's time in an already rather slow process.
>
> It would have been *very* nice in that situation to have a proper apply.

I must be a bit slow today (that wouldn't surprise me), but I can't
seem to replicate anything even remosely close to your problem (in
7.5, 7.6 or 8.0a2). Could you supply some more information?

NB, I fail to see how the foreach/lappend could have helped, as that
would have just split the list up and then rebuilt the list...

Donal.
--
Donal K. Fellows http://r8h.cs.man.ac.uk:8000/ (SAY NO TO COMMERCIAL SPAMS!)
(work) fell...@cs.man.ac.uk Dept. Comp. Sci, Univ. Manchester, U.K.
| do...@ugglan.demon.co.uk 6,Randall Place, Heaton, Bradford, U.K. (home)
+-> ++44-161-275-6137 Send correspondence to my office ++44-1274-401017 <-+

Hume Smith

unread,
Feb 4, 1997, 3:00:00 AM2/4/97
to

In article <5d78tc$9...@m1.cs.man.ac.uk> fell...@cs.man.ac.uk (Donal K. Fellows) writes:

> I must be a bit slow today (that wouldn't surprise me), but I can't
> seem to replicate anything even remosely close to your problem (in
> 7.5, 7.6 or 8.0a2). Could you supply some more information?

okey dokey.

i would define a proc like this:
proc render {canvas price thing} {
$canvas create text ... -text $price ...
$canvas create text ... -text $thing ...
}
then somewhere in the fancylist insert handler would be
foreach i $args {
... ;# some setup
catch {eval $command $i}
... ;# position the new items
}
to make it clear eval gets in there, although
foreach i $args { ... catch [concat $command $i] ... }
is essentially identical. i would call the fancylist with something like
.fl insert end {$12.0 turkey} {$50 potatoes}
so that args would go into the foreach as if it had been
set args {{$12.0 turkey} {$50 potatoes}}
and so we'd do
eval {render renamed-.canvas} {$12.0 turkey}
and fail because there's no variable named 12; because of the catch
i'd just get a blank widget. maybe it'd've been better if i'd let the
eval fail, but the point is, that the substitution eval was doing
was unwanted; it made no sense in that context. but it's the only
way to burst the list into render's arguments.

> NB, I fail to see how the foreach/lappend could have helped, as that
> would have just split the list up and then rebuilt the list...

remember that when extracting an element from a list, several list
representations will give the same elements:

% set z {$12 glob [toy fob] { 16 12} "hello there"}
$12 glob [toy fob] { 16 12} "hello there"
% foreach i $z { lappend l $i }
% set l
{$12} glob {[toy} fob\] { 16 12} {hello there}
% foreach i $z j $l { puts -nonewline [string compare $i $j] }
000000%

clearly l and z are lindex-by-lindex equivalent, while not being the
same string. let's not argue about whether $z is "really a list".

i was interested solely in having the list decomposed into arguments; i did
not want them evaluated as well. i'll repeat: the evaluation made no sense
in that context, only the list burst.

yes, once the program that used my fancylist was completed, all the
insert arguments were constructed with list commands, and i didn't
*need* to requote them internally anymore. but it sure would be nice
to have an apply that just broke lists up into an - what to call it, an
imperative? - without doing anything with $, [, ;, etc as well. it would
surely be faster internally and externally - ie execution and setup, not
having to do that foreach business to be absolutely safe.

Norman Richards

unread,
Feb 4, 1997, 3:00:00 AM2/4/97
to

In article <5crncm$f...@plath.bain.oz.au>,

James Cribb <jam...@bain.oz.au> wrote:
>Norman Richards (o...@cs.utexas.edu) wrote:
>: proc apply {command arglist} {
>: return [eval [concat [list $command] $arglist]]
>: }
>
>Almost, but
>
> % llength {[puts boom]}
> 2
> % apply llength {[puts boom]}
> boom
> 0

Ouch. Yes. You would have to have a proper list in this case.

Brent B. Welch

unread,
Feb 4, 1997, 3:00:00 AM2/4/97
to

n...@slothrop1.mitre.org (Jay A. Carlson) writes:

>In article <5cgeal$t...@crl13.crl.com>, Joe English <jeng...@crl.com> wrote:

>This is one of my pet peeves in Tcl. I've started writing this at
>least three times on my own.

>I have a procedure that opens an xterm. Users suggest that I give


>them the ability to optionally set the title and icon name of the
>xterm.

>Anyway, what I *wanted* to write in the first place was:

>proc openXterm {{title ""} {iconname ""}} {
> set cmdargv [list xterm -bg Blue -fg White]
> if {$title != ""} {
> lappend cmdargv "-T" $title
> }
> if {$iconname != ""} {
> lappend cmdargv "-n" $iconname
> }
> lappend cmdargv "&"

> apply exec $cmdargv
>}

>which should cleanly handle anything a user would stuff into $title.

The above code will work if you start out cmdargv with exec

set cmdargv [list exec xterm -bg Blue -fg White]

and then use

eval $cmdargv

Because eval only gets a single argument, it doesn't do
any nasty concats and the list structure you created is
passed directly to the execve system call.

--
-- Brent Welch Sun Labs brent...@eng.sun.com

Bryan Kramer

unread,
Feb 6, 1997, 3:00:00 AM2/6/97
to

A very big reason for having apply is to avoid unnecessary conversions
to strings.

The command

apply $someproc $arglist

will be byte compiled and the list will a binary object which can
trivially mapped into the argv structure of the proc.

eval $someproc $arglist

will however have to convert the list to a string. This list could be a
very complicated structure - at the top level it's only going to have a
few elements (because procs generally don't have very many arguments),
but lower levels could have thousands of bytes of information (consider
a proc whose first argument is a list of a thousand elements -- this
won't be impossible now that the cost of using lists is reasonable with
the binary representation)

--
|Bryan M. Kramer, Ph.D. 416-592-8865, fax 416-592-8802|
|Ontario Hydro, 700 University Avenue, H12-C1 |
|Toronto, Ontario, Canada M5G 1X6 |
<A href="http://www.cs.toronto.edu/~kramer">B. Kramer Home Page</A>

Mark Crimmins

unread,
Feb 6, 1997, 3:00:00 AM2/6/97
to

My vote: yay for "apply". I've been bitten by "eval"
pretty often trying just to pass arguments.

By the way, someone posted what looked like a good
tcl-only stop-gap solution (I think with regsubs for protecting
special characters). I can't dig it up now. Anyone
have it?

Thanks,
Mark

--
mark...@umich.edu

Hume Smith

unread,
Feb 7, 1997, 3:00:00 AM2/7/97
to

In article <32FA4350...@umich.edu> Mark Crimmins <mark...@umich.edu> writes:

> My vote: yay for "apply". I've been bitten by "eval"
> pretty often trying just to pass arguments.
>
> By the way, someone posted what looked like a good
> tcl-only stop-gap solution (I think with regsubs for protecting
> special characters). I can't dig it up now. Anyone
> have it?

no regsubs in mine, but you can find my apply 7.6 C code, its Tcl
near-equivalent, and a lisp-backquote-like proc on my tcl page:
<URL:http://dess.tallships.istar.ca/%7Ehclsmith/plugin.html>

Cameron Laird

unread,
Feb 9, 1997, 3:00:00 AM2/9/97
to

In article <5crncm$f...@plath.bain.oz.au>,
James Cribb <jam...@bain.oz.au> wrote:
.
.
.

>Also, the "return" is redundant. How about this:
>
> % proc apply {command arglist} {
> eval [concat [list $command] [list $arglist]]
> }
.
.
.
How *do* people feel about the return-value-is-
implicitly-whatever's-left-on-the-stack rule?
I think it contributes usefully to readability
to make it explicit, and write

return eval [...

rather than

eval [...

A lot of that bias might well come from working
in a multi-language development environment,
where not everyone will remember all the defini-
tions.

I'm tempted to cross-post this to c.l.m and/or
c.s-e, because other (HL, all?) languages have
the same rule, and also because this relates to
a couple of other return questions I have that
are a bit more profound.
--

Cameron Laird http://starbase.neosoft.com/~claird/home.html
cla...@NeoSoft.com +1 713 623 8000 #227
+1 713 996 8546 FAX

Donal K. Fellows

unread,
Feb 10, 1997, 3:00:00 AM2/10/97
to

In article <5d66cu$l...@news.istar.ca>,
Hume Smith <hcls...@tallships.istar.ca> wrote:
[ Elided ]
> My idea of apply is that, lindex for lindex, apply list ... should be the

> same as concat ...
> proc apply {args} {
> foreach i $args { foreach j $i { lappend l $j } }
> eval $l
> }

[ Examples elided ]

Ah! I see. The problem seems to be that eval (the compiler
actually), when passed a single list object insists on converting it
to a string and then parsing it back into commands, despite the fact
that usually that isn't necessary. If the compiler supported a more
direct conversion of lists to byte-codes (or if the compilation step
was omitted altogether for this special case) then that would make the
above implementation of apply pretty close to as efficient as it is
reasonable to expect.

Hmm. Examination of the source to Tcl8.0a2 (specifically
.../generic/tclBasic.c and .../generic/tclUtil.c) indicates that
concatenation (as performed by concat) is not performed on lists, but
rather strings instead - contrary to the manpage for concat. This may
well be a source of bugs - yes, it is as it allows the concatenation of
strings which are not lists (something which should be placed in the
preserve of the join command)

$ tclsh8.0
% concat "foo {" "bar }"
foo { bar }
% llength [concat "foo {" "bar }"]
2
% llength "foo {"
unmatched open brace in list

Neil Walker

unread,
Feb 10, 1997, 3:00:00 AM2/10/97
to

Cameron Laird wrote:
> How *do* people feel about the return-value-is-
> implicitly-whatever's-left-on-the-stack rule?
> I think it contributes usefully to readability
> to make it explicit ...

As well as improving readability, if tcl required a "return", then
the compiler could check for it!

[An example Gotcha is when you have a proc ending in a conditional,
and you forget to put a sensible return value in that rarely used
elseif clause ...]

I'd definitely be in favour of something like gcc's -Wall (or even
-pedantic) for allow for some extra checking for the sloppy-of-coding!

Cheers
Neil

Heribert Dahms

unread,
Feb 11, 1997, 3:00:00 AM2/11/97
to

In <5dm06o$b...@Starbase.NeoSoft.COM> cla...@Starbase.NeoSoft.COM
(Cameron Laird) writes:

: How *do* people feel about the return-value-is-


: implicitly-whatever's-left-on-the-stack rule?
: I think it contributes usefully to readability

: to make it explicit, and write
[snip]

I don't know yet how 8.0 handles this, but the docu of the ICE Tcl compiler
explicitly says it could generate better C code if you always use "return"
and confirm this with a compiler switch.


Bye, Heribert (da...@ifk20.mach.uni-karlsruhe.de)

Donal K. Fellows

unread,
Feb 19, 1997, 3:00:00 AM2/19/97
to

In article <5d7ot4$g...@news.istar.ca>,
Hume Smith <hcls...@tallships.istar.ca> wrote:
[ Loads elided ]

> yes, once the program that used my fancylist was completed, all the
> insert arguments were constructed with list commands, and i didn't
> *need* to requote them internally anymore. but it sure would be nice
> to have an apply that just broke lists up into an - what to call it, an
> imperative? - without doing anything with $, [, ;, etc as well. it would
> surely be faster internally and externally - ie execution and setup, not
> having to do that foreach business to be absolutely safe.

I thought I wasn't getting bitten by this sort of problem, and indeed,
I wasn't up until Tcl8, when I found that code which was reasonably
nippy in 7.6 started to run like a drain in 8.0, and the culprit was
the fact that I had a _lot_ of uses of the following construct (well,
actually it's equivalent in C):

proc foo {arg cmd args} {
global lookup
set x [eval [list $lookup($arg,$cmd) $arg] $args]
}

and so I've just written some code to speed this up by skipping past
the need for the eval in there, so allowing calls to be performed
without loads of extra fiddling around with converting long lists to
and from strings in an unpleasantly deep call-structure...

The code is at:
http://r8h.cs.man.ac.uk:8000/tcl/

0 new messages