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

TIP #57: Multiple Assignment Command

6 views
Skip to first unread message

Agnar Renolen

unread,
Aug 30, 2001, 1:46:51 PM8/30/01
to

TIP #57: MULTIPLE ASSIGNMENT COMMAND
--------------------------------------
Version: $Revision: 1.2 $
Author: Agnar Renolen <agnar....@emap.no>
State: Draft
Type: Project
Tcl-Version: 8.4
Vote: Pending
Created: Thursday, 30 August 2001
URL: http://purl.org/tcl/tip/57.html
WebEdit: http://purl.org/tcl/tip/edit/57
Post-History:

-------------------------------------------------------------------------

ABSTRACT
----------

This TIP proposes a new function _mset_ (or a modification to _set_) to
perform multiple assignment.

INTRODUCTION
--------------

In many cases, a command needs to return more than one return value to
the caller. For example, suppose that the statement:

set coords [LocateFeature $featureID]

would set the variable "coords" to a list containing two elements "x"
and "y". Assume that you need to set the "x" and "y" components
directly, you can do this today using the following statement:

foreach {x y} [LocateFeature $featureID] {}

Now, this is not what the _foreach_ command was designed for, and it is
not obvious at first glance from the source code what the statement
does. Although it is quite useful for the purpose described in this
TIP, It would be more logical if the developer could write the
following:

set {x y} [LocateFeature $featureID]

or

mset {x y} [LocateFeature $featureID]

DESIGN ALTERNATIVES
---------------------

The following Tcl code is an implementation I have made myself for
_mset_. Because it returns the remaining elements in the list that were
not assigned to a value, the proposed specification is not suitable as
an extension to _set_, but rather as a new command _mset_.

##
# mset - set multiple variables with values from a list
#
# SYNOPSIS
# [mset <varlist> <valuelist>]
#
# DESCRIPTION
# Sets multiple variables with values from a list. The <varlist>
# contains variable names and each variable will be assigned the
# corresponding value in <valuelist>. For example
#
# [mset \{name age sex\} \{Bill 42 male\}]
#
# It is an error if <valuelist> contains fewer elements than the
# <varlist>. If the valuelist contains more elements than the
# <varlist> the exceeding values will not be assigned to any
# variable.
#
# The procedure returns the a list containing the remaining
# elements in <valuelist> that were no assigned to a variable.
##

proc misc::mset {varList valueList} {
if {[llength $varList] > [llength $valueList]} {
error "mset error: more variables than values"
}
set i 0
foreach varName $varList {
upvar $varName var
set var [lindex $valueList $i]
incr i
}
return [lrange $valueList 0 [expr $i - 1]]
}

If _set_ is extended rather than introducing a new _mset_ command, it
should return a list comprising the elements that were set, so

set {name age} {Bill 42 male developer}

would return the list,

{Bill 42}

while

mset {name age} {Bill 42 male developer}

as specified above, would return:

{male developer}

EVALUATION OF ALTERNATIVES
----------------------------

Since the syntax proposed for an extended _set_ command would produce
an error in its current form, it will create no problems of backward
compatibility. Returning the list of the elements that were assigned to
variables would also be consistent with the current _set_ command.

The advantage of the _mset_ command is that it provides a convenient
way to take care of exceeding values when you have assigned the first
values to variables. However, because it is inconsistent with the _set_
command in terms of the returned vale, it should be implemented as a
different command.

A third theoretical alternative is to implement a new _mset_ command
having the specification outlined for the extended _set_ command.
Personally, I think it is unnecessary to introduce a new command when
you can extend an existing function consistently and without problems
with backward compatibility.

COPYRIGHT
-----------

This document is placed in the public domain.

-------------------------------------------------------------------------

TIP AutoGenerator - written by Donal K. Fellows

[[Send Tcl/Tk announcements to tcl-an...@mitchell.org
Send administrivia to tcl-announ...@mitchell.org
Announcements archived at http://groups.yahoo.com/group/tcl_announce/
The primary Tcl/Tk archive is ftp://ftp.neosoft.com/pub/tcl/ ]]

Cameron Laird

unread,
Aug 30, 2001, 3:06:14 PM8/30/01
to
In article <pgpmoose.2001...@non.non.net>,
Agnar Renolen <tcl-...@lists.sourceforge.net> wrote:
.
.
.

> Now, this is not what the _foreach_ command was designed for, and it is
> not obvious at first glance from the source code what the statement
> does. Although it is quite useful for the purpose described in this
> TIP, It would be more logical if the developer could write the
> following:
>
> set {x y} [LocateFeature $featureID]
>
> or
>
> mset {x y} [LocateFeature $featureID]
>
> DESIGN ALTERNATIVES
>---------------------
>
> The following Tcl code is an implementation I have made myself for
> _mset_. Because it returns the remaining elements in the list that were
> not assigned to a value, the proposed specification is not suitable as
> an extension to _set_, but rather as a new command _mset_.
>
> ##
> # mset - set multiple variables with values from a list
> #
> # SYNOPSIS
> # [mset <varlist> <valuelist>]
.
.
.
Why should I prefer this over the more traditional lassign
<URL: http://mini.net/tcl/lassign > ?
--

Cameron Laird <cla...@NeoSoft.com>
Business: http://www.Phaseit.net
Personal: http://starbase.neosoft.com/~claird/home.html

David Gravereaux

unread,
Aug 30, 2001, 3:30:45 PM8/30/01
to
Agnar Renolen <agnar....@emap.no> wrote:

> Assume that you need to set the "x" and "y" components
> directly, you can do this today using the following statement:
>
> foreach {x y} [LocateFeature $featureID] {}
>
> Now, this is not what the _foreach_ command was designed for, and it is
> not obvious at first glance from the source code what the statement
> does.

I like your idea very much. The first time I saw foreach used that way, I had
to stare at it for about 5 minutes while pondering it deeply...

Please mention, a bit more strongly, in the 'EVALUATION OF ALTERNATIVES' section
that mset above all (maybe) increases readability :)
--
David Gravereaux <davy...@pobox.com>

Stephen Trier

unread,
Aug 30, 2001, 4:18:19 PM8/30/01
to
The proposed syntax for an extended set command isn't fully backwards
compatible. Variable names with spaces are legal and have well-defined
behavior in Tcl:

C:\work\commboot>tclsh83
% info patchlevel
8.3.0
% info vars a*
argv argv0 auto_oldpath auto_path auto_index argc
% set {a b} {foo bar}
foo bar
% info vars a*
argv argv0 {a b} auto_oldpath auto_path auto_index argc
% puts ${a b}
foo bar
% puts [set {a b}]
foo bar

The proposed syntax also introduces an odd conceptual break between
set-as-assignment, which would now take a list as its first argument,
and set-as-variable-access, which takes a string:

set {{a b}} foo ;# Assigns a value to {a b}
but
set {a b} ;# Returns the value of {a b}

If set is to be extended, it would be better to use multiple
arguments, one per variable:

set a b {foo bar}
# Equivalent to
# set a foo
# set b bar

set a {b c} {foo bar}
# Equivalent to
# set a foo
# set {b c} bar

With this syntax, currently legal uses of set won't break and the
symmetry between assignment and variable access will be preserved.

Cameron pointed out TclX's lassign. This syntax is equivalent to
lassign. Since there is code in the world already using lassign, it
would probably be better simply to move lassign to the core.

Stephen

--
Stephen Trier
s...@po.cwru.edu
KG8IH

Bryan Oakley

unread,
Aug 30, 2001, 4:58:43 PM8/30/01
to
> Since the syntax proposed for an extended _set_ command would produce
> an error in its current form, it will create no problems of backward
> compatibility. Returning the list of the elements that were assigned to
> variables would also be consistent with the current _set_ command.

No. Right now this is perfectly valid for the set command:

set {name age} {Bill 42 male developer}

If set were changed according to your specs, this would "break" the above
code (ie: it would do something different than it used to).

set should definitely *not* be modified in this manner.

Even though it's not common to create variables with names that look like
lists doesn't mean it doesn't happen.


Anselm Lingnau

unread,
Aug 30, 2001, 6:17:16 PM8/30/01
to
Stephen Trier <ste...@prozac.eeap.cwru.edu> wrote:

> The proposed syntax for an extended set command isn't fully backwards
> compatible. Variable names with spaces are legal and have well-defined

> behavior in Tcl: [...]

This is what I was going to point out.

We could extend the »set« command such that it would work like the
»variable« command, i.e.,

set a 123 b 456 c 789

would assign »123« to »a«, »456« to »b«, and »789« to c. This would
leave the current functionality, which relies on there being either
exactly one or exactly two arguments, alone and would be fully
backwards compatible.

> Cameron pointed out TclX's lassign. This syntax is equivalent to
> lassign. Since there is code in the world already using lassign, it
> would probably be better simply to move lassign to the core.

Possibly. Or we could continue to use the »foreach« hack for assigning
the contents of a list element-wise to a bunch of variables. The
syntax above would mostly be useful to save some lines of code when
doing multiple assignments.

Anselm
--
Anselm Lingnau .......................................... ans...@strathspey.org
Then I realized that I had spelled `-' wrong. -- John Whitmore learns APL

Kenneth H. Cox

unread,
Aug 30, 2001, 9:12:41 PM8/30/01
to
Agnar Renolen wrote:

> It would be more logical if the developer could write the
> following:
>
> set {x y} [LocateFeature $featureID]

A developer can write the following, only now it creates a variable name
which has a space in it. Try it:

set {x y} a
info vars x*

Therefore the only practical alternative is [mset].

Regards,
Ken


Martin Lemburg

unread,
Aug 31, 2001, 2:38:45 AM8/31/01
to
> > # [mset <varlist> <valuelist>]
> .
> .
> .
> Why should I prefer this over the more traditional lassign
> <URL: http://mini.net/tcl/lassign > ?

I know, why I should prefer this in-core solution ...
.... we use tcl very intensively in our software, but we avoid
completely the usage of 3rd party extensions/packages!

We use the standard tcl command interface and the standard
C API and not more and I think that other companies act the
same way.

And ... an "batteries included"-distribution is quiet nice,
but we only deliver our products with a standard tcl distri-
bution.

So ... any clean in-core solution for common problems or
uncomfortablenesses are absolutely to be prefered!

Regards

UGS
Martin Lemburg
Software Engineer
Unigraphics Solutions GmbH
e-Factory line of business simulation & analysis products
Alt-Moabit 96C // 5. OG.
D-10559 Berlin

Tel: +49 (0) 30 46 77 75 - 22
Fax: +49 (0) 30 46 77 75 - 11
Mobil: +49 (0) 179 395 40 95

m...@dcade.de
martin....@ugs.com

http://www.ugsolutions.de
http://www.ugs.com

Donal K. Fellows

unread,
Aug 31, 2001, 5:25:26 AM8/31/01
to tcl-...@lists.sourceforge.net
Anselm Lingnau wrote:

> Stephen Trier <ste...@prozac.eeap.cwru.edu> wrote:
>> Cameron pointed out TclX's lassign. This syntax is equivalent to
>> lassign. Since there is code in the world already using lassign, it
>> would probably be better simply to move lassign to the core.
>
> Possibly. Or we could continue to use the »foreach« hack for assigning
> the contents of a list element-wise to a bunch of variables. The
> syntax above would mostly be useful to save some lines of code when
> doing multiple assignments.

I use the [foreach] hack a lot in my own code, but it is only really a
satisfactory solution when the number of variables is properly matched
to the number of values. The rest of the time, it is not brilliant at
all.

By contrast, [lassign] has clear semantics that should be pretty easy
for even beginners to grasp. It also lets you implement things like
[shift] (recognisable to Shell and Perl hackers) very easily:

proc shift {} {
global argv
set argv [lassign $argv v]
return $v
}

Donal.
--
"Understanding leads to tolerance, which in turn leads to acceptance. And from
there, it's just a quick hop to speeding in Ohio, chewing peyote, and
frottage in the woods with a family of moose. And I just want to claim my
part of the credit." -- bunnythor <bunn...@uswest.net>

Hemang Lavana

unread,
Aug 31, 2001, 9:20:26 AM8/31/01
to
> By contrast, [lassign] has clear semantics that should be pretty easy
> for even beginners to grasp. It also lets you implement things like
> [shift] (recognisable to Shell and Perl hackers) very easily:
>
> proc shift {} {
> global argv
> set argv [lassign $argv v]
> return $v
> }

Note that Tclx also has the [lvarpop] command which is equivalent to the
[shift] command you describe here.

Hemang.

lvi...@yahoo.com

unread,
Aug 31, 2001, 10:01:37 AM8/31/01
to

According to Martin Lemburg <martin....@ugs.com>:
:> > # [mset <varlist> <valuelist>]

:> .
:> .
:> .
:> Why should I prefer this over the more traditional lassign
:> <URL: http://mini.net/tcl/lassign > ?
:
:I know, why I should prefer this in-core solution ...
:.... we use tcl very intensively in our software, but we avoid
:completely the usage of 3rd party extensions/packages!
:
:We use the standard tcl command interface and the standard
:C API and not more and I think that other companies act the
:same way.

So why not just use the same name, and propose it be added to the Tcl core?

--
--
"See, he's not just anyone ... he's my son." Mark Schultz
<URL: mailto:lvi...@cas.org> <URL: http://www.purl.org/NET/lvirden/>
Even if explicitly stated to the contrary, nothing in this posting

Andreas Kupries

unread,
Aug 31, 2001, 10:07:40 AM8/31/01
to

"Martin Lemburg" <martin....@ugs.com> writes:

> > > # [mset <varlist> <valuelist>]
> > .
> > .
> > .
> > Why should I prefer this over the more traditional lassign
> > <URL: http://mini.net/tcl/lassign > ?

> I know, why I should prefer this in-core solution ... .... we use
> tcl very intensively in our software, but we avoid completely the
> usage of 3rd party extensions/packages!

What about pure-tcl extensions, like tcllib ?



> We use the standard tcl command interface and the standard C API and
> not more and I think that other companies act the same way.

> And ... an "batteries included"-distribution is quiet nice, but we
> only deliver our products with a standard tcl distri- bution.

What is the reason for this policy of severe restriction ? Especially
as that cuts you off from any help you can gain from the outside. I
mean, whenever you need something for which we already have an
extension you have to reinvent it for yourself, which takes time,
money, IOW resources. Or you don't reinvent, in that case you simply
lose opportunities.

--
Sincerely,
Andreas Kupries <akup...@home.com>
Developer @ <http://www.activestate.com/>
Private <http://www.purl.org/NET/akupries/>
-------------------------------------------------------------------------------
}

Ludwig Callewaert

unread,
Aug 31, 2001, 10:41:34 AM8/31/01
to
Andreas Kupries wrote:
>
>
> > I know, why I should prefer this in-core solution ... .... we use
> > tcl very intensively in our software, but we avoid completely the
> > usage of 3rd party extensions/packages!
>
> What about pure-tcl extensions, like tcllib ?
>
> > We use the standard tcl command interface and the standard C API and
> > not more and I think that other companies act the same way.
>
> > And ... an "batteries included"-distribution is quiet nice, but we
> > only deliver our products with a standard tcl distri- bution.
>
> What is the reason for this policy of severe restriction ? Especially
> as that cuts you off from any help you can gain from the outside. I
> mean, whenever you need something for which we already have an
> extension you have to reinvent it for yourself, which takes time,
> money, IOW resources. Or you don't reinvent, in that case you simply
> lose opportunities.

Martin's company is indeed not alone in this.

We use a similar policy, but not as severe as Martin's does. Only those
extensions that are actively maintained are considered in being used.
And even then the number of extensions are kept at a strict minimum.
Adding TclX just because it has an lassign would never be considered
for instance.

You are right that re-inventing the wheel takes resources. But
having to redevelop the wheel because the one you used no longer fits
on your new car can take even more resources. And believe me we have
had to do this.

The problem is that extensions are not guaranteed to be maintained.
When that happens for an extension, you have the option of maintaining
it yourself or switch to something else. Both are costly.

We do hope that the BI distribution will improve this situation, as long
as all extensions present in that distribution operate together.

Unfortunately for us, the BI distribution does not contain BLT at this moment
(at least as far as I know).

--

Ludwig Callewaert e-mail: ludwig_c...@frontierd.com
Senior Software Engineer Frontier Design, Belgium
__________________________________________________________________

Donal K. Fellows

unread,
Aug 31, 2001, 11:16:12 AM8/31/01
to
Hemang Lavana wrote:
> Note that Tclx also has the [lvarpop] command which is equivalent to the
> [shift] command you describe here.

[shift] != [lvarpop]; [shift] == [lvarpop ::argv]

Larry Smith

unread,
Aug 31, 2001, 11:59:55 AM8/31/01
to
Cameron Laird wrote:

> In article <pgpmoose.2001...@non.non.net>,
> Agnar Renolen <tcl-...@lists.sourceforge.net> wrote:
.

> > Now, this is not what the _foreach_ command was designed for

> > # [mset <varlist> <valuelist>]
.


> Why should I prefer this over the more traditional lassign

If we're going to consider adding a new command, I'd
very much like to see something a bit more sophisticated.

Anyone using my Tcl-tool has seen my solution to this
problem, and I offer it as one good alternative:

The "let" command from tcl-tools allows you to assign
multiple variables, but is more elegant and flexible
in processing what you are going to assign.

"let" takes a list of vars, and assignment op, and a
list. The vars will be assigned, the assignment op
indicates how the assignment is done and what happens
to the list in the process.

Expressions:

let a b c = 2 + 5

foreach is replaced with a "hoisting" assignment:

let a b c @= $list

command evaluation:

let cmdlist := info commands

The above two can be combined to unpack a list
result from a command:

let firstcmd secondcmd thirdcmd @:= info commands

computed assignment:

let a += 1

+=, -=, *=, /=, &=, and |= are supported and you
can do multiple vars, of course:

let a b += 1

Very handy for dragging indexes through lists.

And, just for the heck of it, let can also do inc
and dec:

let a ++
let b --

as a conceptual replacement for incr, set, and a big
hunk of foreach, I think it's a lot more elegant.

--
.-. .-. .---. .---. .-..-. | Wild Open Source Inc.
| |__ / | \| |-< | |-< > / | "Making the bazaar just a
`----'`-^-'`-'`-'`-'`-' `-' | little more commonplace."
http://www.smith-house.org/ | Need programming? Ask me.

Jeff Hobbs

unread,
Aug 31, 2001, 1:02:59 PM8/31/01
to
"Donal K. Fellows" wrote:
...

> I use the [foreach] hack a lot in my own code, but it is only really a
> satisfactory solution when the number of variables is properly matched
> to the number of values. The rest of the time, it is not brilliant at
> all.

That's what break is good for. I always do:

foreach {a b c} $list { break }

then you are ensured that a,b,c only get set the first time.

--
Jeff Hobbs The Tcl Guy
Senior Developer http://www.ActiveState.com/
Tcl Support and Productivity Solutions

Dan Smart

unread,
Aug 31, 2001, 10:52:14 PM8/31/01
to
Jeff Hobbs <Je...@ActiveState.com> wrote in
news:3B8FC343...@ActiveState.com:

> "Donal K. Fellows" wrote:
> ...
>> I use the [foreach] hack a lot in my own code, but it is only really a
>> satisfactory solution when the number of variables is properly matched
>> to the number of values. The rest of the time, it is not brilliant at
>> all.
>
> That's what break is good for. I always do:
>
> foreach {a b c} $list { break }
>
> then you are ensured that a,b,c only get set the first time.
>

I'm not sure that "good for" is exactly the phrase I'd have chosen. I think
I'd have phrased that as "While you're abusing foreach as an assignment
statement, you should remember to abuse break as follows, to avoid
unexpected side effects."

Dan "Purple Telephone" Smart.
--
Dan Smart. C++ Programming and Mentoring.
cpp...@dansmart.com

Ed Ohsone

unread,
Sep 1, 2001, 3:01:18 PM9/1/01
to
"Donal K. Fellows" <fell...@cs.man.ac.uk> writes:

[snip]

> I use the [foreach] hack a lot in my own code, but it is only really a
> satisfactory solution when the number of variables is properly matched
> to the number of values. The rest of the time, it is not brilliant at
> all.
>
> By contrast, [lassign] has clear semantics that should be pretty easy
> for even beginners to grasp.

[snip]


I was using foreach for multiple assignment for quite a while.
But after measuring performance difference between mutiple set statements
and foreach I stopped using foreach for that purpose.
foreach is slower than multiple set when number of assignments is less
than 10 on my platform.
The overhead of foreach is just too big to justify its use in many cases.

The following is a test result on my aged platform (P2 266Mhz linux 2.2.16).
You can test in your environment with the script I attached below.

It shows foreach is slower when the number of assignments is less than 10.

(milliseconds in 5000 iterations)

---------- 15 items ----------
foreach (scalar) = 220
multiple set (scalar) = 238

array set (array) = 268
multiple set (array) = 284

---------- 10 items ----------
foreach (scalar) = 173
multiple set (scalar) = 177

array set (array) = 213
multiple set (array) = 209

---------- 5 items ----------
foreach (scalar) = 131
multiple set (scalar) = 118

array set (array) = 158
multiple set (array) = 136


By the way if you are to add a new multiple assignment command to
the core, I do not think the formats used in lassign and foreach
are good for this purpose.

It is because they do not show variable-value pair clearly.
In the past whenever I used foreach for multiple assignment only,
I had to pay extra attention to avoid error, as you can see in the
below example. Moreover it made code ugly and less readable.

# ------- foreach ----------
foeach {a b c d ...} \
[list [some command line] some_value [some command line] some_value ...] {}

# ------- this is cleaner and safer ----------
set a [some command line]
set b some_value
set c [some command line]
set d some_value
...

I suggest the new lassign in the core use the format of "array set"
which shows the variable-value pairs clearly like:

new_lassign \
var1 valu1
var2 [command line]
var3 value3
var4 [command line]
...

Finally, I see little benefit in having a new lassign in tcllib.
If you need a lassign you can easily write one in tcl for your app.

The only factor that made me avoid multiple set was performance.
(Now I am using mutiple sets for the same reason.)
At least to me only C-coded lassign makes sense.

---------
Ed


--------------- test script -----------------


puts "\n---------- 15 items ----------"

# ----- scalar -----
set start [clock clicks -milliseconds]
for {set i 0} {$i < 5000} {incr i} {
foreach {v1 v2 v3 v4 v5 v6 v7 v8 v9 v10 v11 v12 v13 v14 v15}\
{1 2 3 4 5 6 7 8 9 10 11 12 13 14 15} {}
}

set end [clock clicks -milliseconds]
puts "foreach (scalar) = [expr {$end-$start}]"


set start [clock clicks -milliseconds]
for {set i 0} {$i < 5000} {incr i} {
set v1 1
set v2 2
set v3 3
set v4 4
set v5 5
set v6 6
set v7 7
set v8 8
set v9 9
set v10 10
set v11 11
set v12 12
set v13 13
set v14 14
set v15 15
}

set end [clock clicks -milliseconds]
puts "multiple set (scalar) = [expr {$end-$start}]"

# ----- array -----

set tmp(x) ""

set start [clock clicks -milliseconds]
for {set i 0} {$i < 5000} {incr i} {
array set tmp\
{1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10
11 11 12 12 13 13 14 14 15 15}
}

set end [clock clicks -milliseconds]
puts "\narray set (array) = [expr {$end-$start}]"

set start [clock clicks -milliseconds]
for {set i 0} {$i < 5000} {incr i} {
set tmp(1) 1
set tmp(2) 2
set tmp(3) 3
set tmp(4) 4
set tmp(5) 5
set tmp(6) 6
set tmp(7) 7
set tmp(8) 8
set tmp(9) 9
set tmp(10) 10
set tmp(11) 11
set tmp(12) 12
set tmp(12) 13
set tmp(12) 14
set tmp(12) 15

}

set end [clock clicks -milliseconds]
puts "multiple set (array) = [expr {$end-$start}]"


puts "\n---------- 10 items ----------"

# ----- scalar -----
set start [clock clicks -milliseconds]
for {set i 0} {$i < 5000} {incr i} {
foreach {v1 v2 v3 v4 v5 v6 v7 v8 v9 v10}\
{1 2 3 4 5 6 7 8 9 10} {}
}

set end [clock clicks -milliseconds]
puts "foreach (scalar) = [expr {$end-$start}]"


set start [clock clicks -milliseconds]
for {set i 0} {$i < 5000} {incr i} {
set v1 1
set v2 2
set v3 3
set v4 4
set v5 5
set v6 6
set v7 7
set v8 8
set v9 9
set v10 10
}

set end [clock clicks -milliseconds]
puts "multiple set (scalar) = [expr {$end-$start}]"

# ----- array -----

set tmp(x) ""

set start [clock clicks -milliseconds]
for {set i 0} {$i < 5000} {incr i} {
array set tmp\
{1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10}
}

set end [clock clicks -milliseconds]
puts "\narray set (array) = [expr {$end-$start}]"

set start [clock clicks -milliseconds]
for {set i 0} {$i < 5000} {incr i} {
set tmp(1) 1
set tmp(2) 2
set tmp(3) 3
set tmp(4) 4
set tmp(5) 5
set tmp(6) 6
set tmp(7) 7
set tmp(8) 8
set tmp(9) 9
set tmp(10) 10
}

set end [clock clicks -milliseconds]
puts "multiple set (array) = [expr {$end-$start}]"


puts "\n---------- 5 items ----------"

# ----- scalar -----
set start [clock clicks -milliseconds]
for {set i 0} {$i < 5000} {incr i} {
foreach {v1 v2 v3 v4 v5} {1 2 3 4 5} {}
}

set end [clock clicks -milliseconds]
puts "foreach (scalar) = [expr {$end-$start}]"


set start [clock clicks -milliseconds]
for {set i 0} {$i < 5000} {incr i} {
set v1 1
set v2 2
set v3 3
set v4 4
set v5 5
}

set end [clock clicks -milliseconds]
puts "multiple set (scalar) = [expr {$end-$start}]"

# ----- array -----

set tmp(x) ""

set start [clock clicks -milliseconds]
for {set i 0} {$i < 5000} {incr i} {
array set tmp {1 1 2 2 3 3 4 4 5 5}
}

set end [clock clicks -milliseconds]
puts "\narray set (array) = [expr {$end-$start}]"

set start [clock clicks -milliseconds]
for {set i 0} {$i < 5000} {incr i} {
set tmp(1) 1
set tmp(2) 2
set tmp(3) 3
set tmp(4) 4
set tmp(5) 5
}

set end [clock clicks -milliseconds]
puts "multiple set (array) = [expr {$end-$start}]"


Bruce Hartweg

unread,
Sep 1, 2001, 4:30:48 PM9/1/01
to
Ed Ohsone wrote:

> "Donal K. Fellows" <fell...@cs.man.ac.uk> writes:
>
> [snip]
>
> > I use the [foreach] hack a lot in my own code, but it is only really a
> > satisfactory solution when the number of variables is properly matched
> > to the number of values. The rest of the time, it is not brilliant at
> > all.
> >
> > By contrast, [lassign] has clear semantics that should be pretty easy
> > for even beginners to grasp.
>
> [snip]
>
> I was using foreach for multiple assignment for quite a while.
> But after measuring performance difference between mutiple set statements
> and foreach I stopped using foreach for that purpose.
> foreach is slower than multiple set when number of assignments is less
> than 10 on my platform.
> The overhead of foreach is just too big to justify its use in many cases.
>
> The following is a test result on my aged platform (P2 266Mhz linux 2.2.16).
> You can test in your environment with the script I attached below.
>
> It shows foreach is slower when the number of assignments is less than 10.
>
>

Thanks for the info, and sometime a few milliseconds is needed but usually
that level of performance isn't important (in most user oriented apps anyway)
so The shorter and (once seen/understood) easier to read is better.

> By the way if you are to add a new multiple assignment command to
> the core, I do not think the formats used in lassign and foreach
> are good for this purpose.
>
> It is because they do not show variable-value pair clearly.
> In the past whenever I used foreach for multiple assignment only,
> I had to pay extra attention to avoid error, as you can see in the
> below example. Moreover it made code ugly and less readable.
>
> # ------- foreach ----------
> foeach {a b c d ...} \
> [list [some command line] some_value [some command line] some_value ...] {}
>
> # ------- this is cleaner and safer ----------
> set a [some command line]
> set b some_value
> set c [some command line]
> set d some_value
> ...
>
> I suggest the new lassign in the core use the format of "array set"
> which shows the variable-value pairs clearly like:
>
> new_lassign \
> var1 valu1
> var2 [command line]
> var3 value3
> var4 [command line]
> ...
>

But these are contrived examples, of course if you are starting with
separate values, jamming them into a list & then separating them
out again doesn't make sense. Usually one uses this trick when
the data is ALREADY a list. (some commands return lists - like
$canvas bbox, or database queries which return a row at a time.

so
foreach {x1 y1 x2 y2} [.c bbox all]
is much easier to read (and write) then
set coords [.c bbox all]
set x1 [lindex $coords 0]
set y1 [lindex $coords 1]
set x2 [lindex $coords 2]
set x3 [lindex $coords 3]

And it's FASTER! you're tests were for already separate
values to be assigned. If the values start as a list, then the lindex
operation is needed for individual assignments.
On my PIII 350 running 8.3.3
the following results

% set l {1 2 3 4}
1 2 3 4
% time { foreach {a b c d} $l break } 100000
14 microseconds per iteration
% time { set a [lindex $l 0] ; set b [lindex $l 1] ; set c [lindex $l 2] ; set d [lindex $l 3] } 100000
25 microseconds per iteration
%
(so even small lists are faster with foreach)

Bruce

lvi...@yahoo.com

unread,
Sep 1, 2001, 7:24:00 PM9/1/01
to

According to Ludwig Callewaert <ludwig_c...@frontierd.com>:
:The problem is that extensions are not guaranteed to be maintained.

:When that happens for an extension, you have the option of maintaining
:it yourself or switch to something else. Both are costly.


In fact, this (no guarantees) is true for vendor code, for programming
languages, for automobiles, hard currency, and many other things in
life...

lvi...@yahoo.com

unread,
Sep 2, 2001, 1:55:19 PM9/2/01
to

According to Ed Ohsone <eo...@rahul.net>:
:Finally, I see little benefit in having a new lassign in tcllib.

:If you need a lassign you can easily write one in tcl for your app.

I suspect that argument could be made for almost anything currently in the
library or in the future.

Frankly, I don't WANT to have to write thousands of functions that someone
else has already written, debugged, and documented. I want to write my
application, and have things like lassign, etc. already present...

Jeffrey Hobbs

unread,
Sep 3, 2001, 1:23:25 AM9/3/01
to
Bruce Hartweg wrote:

>
> Ed Ohsone wrote:
> > It shows foreach is slower when the number of assignments is less than 10.
...
> But these are contrived examples, of course if you are starting with
> separate values, jamming them into a list & then separating them
> out again doesn't make sense. Usually one uses this trick when
> the data is ALREADY a list. (some commands return lists - like
> $canvas bbox, or database queries which return a row at a time.
...

> And it's FASTER! you're tests were for already separate
> values to be assigned. If the values start as a list, then the lindex
> operation is needed for individual assignments.

FWIW, you might try this with 8.4a3, where lindex is now an
instruction encoded command (fully byte-compiled). This will
favor the multiple sets (although I don't know by how much).
This is probably worth adding to tclbench.

In any case - I don't worry about speed that much for such
minor things. I would use the foreach regardless for
readability (although lassign would be nice).

Ludwig Callewaert

unread,
Sep 3, 2001, 3:24:27 AM9/3/01
to
lvi...@yahoo.com wrote:
>
> According to Ludwig Callewaert <ludwig_c...@frontierd.com>:
> :The problem is that extensions are not guaranteed to be maintained.
> :When that happens for an extension, you have the option of maintaining
> :it yourself or switch to something else. Both are costly.
>
> In fact, this (no guarantees) is true for vendor code, for programming
> languages, for automobiles, hard currency, and many other things in
> life...

You are definately right about that, but I did express myself wrongly.
First of all, we are using as little vendor code as well for the same
reason. (Although with code you pay maintenance for you get at least the
impression that they cannot leave you dead in the water).

But many extensions are a one person thing. Despite that, the level of
maintenance you get for those extensions is astonishingly high, in many
cases better than what you get with commercial (paid) support. Nevertheless
when that person decides for one reason or another, to stop development
on the extension, it becomes dead in many cases (or at least very little
alive).

An example:
We have seen this happen with Tix which we started using because of the
lack of widgets in Tk (a situation that has not changed yet). Tix was
very little alive for some time (and still does not seem to be all that much
alive).
BWidgets came into play, and although we liked it, we decided to
'roll our own'. Some time after Bwidgets were introduced, their future
became also very uncertain as the original developers dropped support
as I seem to recall. BWidgets seems to be doing alright now, however.

With the commercial products we use (none of them are TCL related BTW),
we have not had this problem so far, but it could happen as well.
The situation will be a little different though. If support for a
commercial product is stopped, that is announced long beforehand, so
you have time to plan a smooth transition.
Unless the vendor stops (or has to stop) all activities at once.
To avoid the latter, we are not using products from obscure vendors,
which have a very limited customer base. For instance we do not expect
Flex, which we use for licensing, to disappear overnight given its
customer base.

Given the 'customer base' for TCL, we do not expect it to disappear
overnight either, although when Ajuba disappeared, we had some
doubts about the future of TCL. But things are improving again.
In the undesirable case that TCL were to dissapear, there would still
be ample time to transition to something else.

So you are right, there are no guarantees ever, just a higher probability
of survival.

Ludwig

Martin Lemburg

unread,
Sep 3, 2001, 5:54:45 AM9/3/01
to
"Andreas Kupries" <akup...@home.com> schrieb im Newsbeitrag
news:87u1yox...@bluepeak.home...
>
> ...

>
> What is the reason for this policy of severe restriction ? Especially
> as that cuts you off from any help you can gain from the outside. I
> mean, whenever you need something for which we already have an
> extension you have to reinvent it for yourself, which takes time,
> money, IOW resources. Or you don't reinvent, in that case you simply
> lose opportunities.
>

It's simple - some of my colleagues are sceptical about the reliability
of OpenSource- or GNU-Software (but don't let us start a discussion
about this) and the guarantee of maintance and support.

It's a kind of company policy not to rely on non-bought software.

So - you are right - we had to reinvent the wheel sometimes to get
benefits, we should have had with 3rd party extensions/packages.

Most of the things we could have future benefits are CORBA, COM
and XML-, FTP-extensions. And even if there are free tcl extensions
or packages I'm sure we will buy e.g. a CORBA-package and derive
only that functionality from this package, that we need in tcl.

Up to now I was not able to change this company policy, but I'm still
trying.

lvi...@yahoo.com

unread,
Sep 3, 2001, 6:05:37 AM9/3/01
to

According to Ludwig Callewaert <ludwig_c...@frontierd.com>:
:lvi...@yahoo.com wrote:
:>
:> According to Ludwig Callewaert <ludwig_c...@frontierd.com>:
:> :The problem is that extensions are not guaranteed to be maintained.
:> :When that happens for an extension, you have the option of maintaining
:> :it yourself or switch to something else. Both are costly.
:>
:> In fact, this (no guarantees) is true for vendor code, for programming
:> languages, for automobiles, hard currency, and many other things in
:> life...
:
:You are definately right about that, but I did express myself wrongly.
:First of all, we are using as little vendor code as well for the same
:reason. (Although with code you pay maintenance for you get at least the
:impression that they cannot leave you dead in the water).

You can buy maintenance for Tcl as well...


:But many extensions are a one person thing. Despite that, the level of


:maintenance you get for those extensions is astonishingly high, in many
:cases better than what you get with commercial (paid) support. Nevertheless
:when that person decides for one reason or another, to stop development
:on the extension, it becomes dead in many cases (or at least very little
:alive).

Agreed. Interestingly enough, we have a number of in-house written programs
where we find ourselves in the same situation - the author has decided
that their current projects are much more important, and so development
and support has become dead. :-(

:With the commercial products we use (none of them are TCL related BTW),

:we have not had this problem so far, but it could happen as well.

A company I know purchased a cross platform commercial library on which
they developed a major product. The company went out of business unexpectedly.
'Luckily' they had contracted the source into escrow, and eventually got it.
Unluckily, the code was very tough to maintain (perhaps a factor in the
company's demise).

Now, amusingly enough, now they are trying to rewrite the whole product
in Java. So far, the effort has taking twice as long as expected. Of course
one of the problems with their effort is marketing changing requirements
hourly...

:So you are right, there are no guarantees ever, just a higher probability
:of survival.

Certainly one cannot give up hope. One must keep trying.

lvi...@yahoo.com

unread,
Sep 3, 2001, 6:22:07 AM9/3/01
to

According to Martin Lemburg <martin....@ugs.com>:
:It's simple - some of my colleagues are sceptical about the reliability

:of OpenSource- or GNU-Software (but don't let us start a discussion
:about this) and the guarantee of maintance and support.
:
:It's a kind of company policy not to rely on non-bought software.

Thank goodness you can buy ActiveState's ActiveTcl (perhaps there are others
similarly packaging Tcl - anyone know) which gets you all sorts of extensions,
etc.

Certainly there are a number of Linux distributions which include Tcl
and extensions - I _assume_ that some of these have maintenance support.

Ludwig Callewaert

unread,
Sep 3, 2001, 6:39:04 AM9/3/01
to
lvi...@yahoo.com wrote:
>
>
> Frankly, I don't WANT to have to write thousands of functions that someone
> else has already written, debugged, and documented. I want to write my
> application, and have things like lassign, etc. already present...
>

I could not agree more. TCL has long been suffering from exactly this. You
can do anything in TCL (or Tk for that matter), and everything has been done
in one or other form by someone. But if you need something, you have to write
it yourself. That is why an extensive set of library functions being released
with TCL (the BI distribution) is in my view critical for the success of TCL.
Perl has this for instance. (Ooopss, I said the ugly word. Now I will go and
wash my mouth with soap).

Donal K. Fellows

unread,
Sep 3, 2001, 6:50:28 AM9/3/01
to
Bruce Hartweg wrote:
> % set l {1 2 3 4}
> 1 2 3 4
> % time { foreach {a b c d} $l break } 100000
> 14 microseconds per iteration
> % time { set a [lindex $l 0] ; set b [lindex $l 1] ; set c [lindex $l 2] ; set d [lindex $l 3] } 100000
> 25 microseconds per iteration
> %
> (so even small lists are faster with foreach)

In tests with 8.4a4CVS (on a fairly slow machine FWIW) I find that there
is no great speed advantage to [foreach] over [lindex] with four
arguments, and there is a maintenance penalty, of course:

% set l [list 1 2 3 4]
1 2 3 4
% proc a {} {global l}
% proc b {} {global l


foreach {a b c d} $l break
}

% proc c {} {global l


set a [lindex $l 0] ; set b [lindex $l 1]
set c [lindex $l 2] ; set d [lindex $l 3]
}

% proc d {} {global l
foreach {a b c d} $l {}
}
% proc test {} {foreach x {a b c d} {puts $x=[time $x 100000]}};test
a=38 microseconds per iteration
b=71 microseconds per iteration
c=74 microseconds per iteration
d=72 microseconds per iteration

The testing procedure chosen gives the fastest performance for reasons
not 100% clear to me right now. A word about the results; the first
procedure is there to measure the cost of any overheads, and the others
form the comparison. This shows that, after allowing for the overheads,
there's about 9% difference between the two in favour of [foreach] with
a slight benefit to including a [break] clause.

<context type="historical">
Of course, at the time that the [foreach] idiom was instituted, it was
*much* faster than the alternative with [lindex]. This was in pre-8.0
days where using [foreach] meant that you split the list(s) only once
instead of (in this case) four times.
</context>

Donal.
-- Itanium-based servers combined with Microsoft's latest server software
offer customers superior performance, greater choice, reliability and
investment protection at significantly lower costs than proprietary
solutions. -- Abhi Talwalkar (Intel VP)

Mark Watson

unread,
Sep 15, 2001, 8:47:47 PM9/15/01
to
In article <87u1yox...@bluepeak.home>, "Andreas Kupries"
<akup...@home.com> wrote:

> "Martin Lemburg" <martin....@ugs.com> writes:
>
...

>> And ... an "batteries included"-distribution is quiet nice, but we only
>> deliver our products with a standard tcl distri- bution.
>
> What is the reason for this policy of severe restriction ? Especially
> as that cuts you off from any help you can gain from the outside. I
> mean, whenever you need something for which we already have an extension
> you have to reinvent it for yourself, which takes time, money, IOW
> resources. Or you don't reinvent, in that case you simply lose
> opportunities.
>

If you use aolserver much (we use it internally), it's a good idea
to stick to core commands - it's not particularly happy with extensions,
or at least the current version isn't.

I'd also like to place a (late) vote for putting lassign in the core.

M

0 new messages