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

Switching the value of two variables

62 views
Skip to first unread message

Cecil Westerhof

unread,
May 30, 2018, 3:44:05 PM5/30/18
to
At a certain point I have to switch the values of two variables. I was
thinking about using:
lassign "$a $b" b a

Is that the correct way, or is there a better way?

--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

Aldo Buratti

unread,
May 30, 2018, 4:33:03 PM5/30/18
to
# It doesn't work!
set a "one two"
set b "three four"
lassign "$a $b" b a
puts $a ;# -> one
puts $b ;# -> two

# The correct way is:
set a "one two"
set b "three four"
lassign [list $a $b] b a
# but I think that a simple swap with a temporary var be far more efficient
set _tmp $a ; set a $b ; set b $_tmp ; unset _tmp

Rich

unread,
May 30, 2018, 4:45:04 PM5/30/18
to
Cecil Westerhof <Ce...@decebal.nl> wrote:
> At a certain point I have to switch the values of two variables. I was
> thinking about using:
> lassign "$a $b" b a
>
> Is that the correct way, or is there a better way?

No, that will fail in various weird and sundry ways the moment either
of a or b contain characters that are also used to represent the string
representation of a list.

If you wanted to be fancy, this might work ok:

lassign [list $a $b] b a

But as the other poster indicated, you would likely be more efficient
just using a temporary.

If you wanted to hide the details, you can make a proc to do a swap:

proc swap {a_in b_in} {
upvar 1 $a_in a
upvar 1 $b_in b
set temp $b
set b $a
set a $temp
}

% set x 42
42
% set y Hello
Hello
% swap x y
Hello
% set x
Hello
% set y
42

Cecil Westerhof

unread,
May 31, 2018, 12:14:04 AM5/31/18
to
In my case both contain an integer, but I agree: code should not
contain a trap like that. In Python you can do:
a, b = b, a

I like that very much, but every language gas his pros and cons.

When I execute:
set timeCount 10000000
time {lassign [list $a $b] b a} $timeCount
time {set _tmp $a ; set a $b ; set b $_tmp ; unset _tmp} $timeCount

I see that the lassign version is a little more efficient. That takes
0.6074245 microseconds per iteration, while the swap version takes
0.7931169 microseconds per iteration. So I go for the correct lassign
version.

Gerald Lester

unread,
May 31, 2018, 12:56:12 AM5/31/18
to
To get a true measure:
1) Wrap each of them in a procedure
2) Call each of the procedures once
3) Do the time on a call to the procedure

This will force the code to be byte compiled -- unless you plan to use
it just once, then who cares.

--
+----------------------------------------------------------------------+
| Gerald W. Lester, President, KNG Consulting LLC |
| Email: Gerald...@kng-consulting.net |
+----------------------------------------------------------------------+

Donal K. Fellows

unread,
May 31, 2018, 1:38:27 AM5/31/18
to
On 31/05/2018 05:56, Gerald Lester wrote:
> To get a true measure:
>   1) Wrap each of them in a procedure
>   2) Call each of the procedures once
>   3) Do the time on a call to the procedure

I'd expect the version with a temporary variable to be faster. Yes, I've
tested it properly and got unsurprising results…

Donal.
--
Donal Fellows — Tcl user, Tcl maintainer, TIP editor.

Cecil Westerhof

unread,
May 31, 2018, 2:59:04 AM5/31/18
to
I will do that.


> This will force the code to be byte compiled -- unless you plan to use
> it just once, then who cares.

It will be probably called about 20 million times, but at the same
time the following will be called about 50 million times:
set a [expr {${m} ** 2 - ${n} ** 2}]
set b [expr {2 * ${m} * ${n}}]
set c [expr {${m} ** 2 + ${n} ** 2}]

So I do not think that timing is an issue here.

Donald Arseneau

unread,
Jun 10, 2018, 1:18:00 AM6/10/18
to
Cecil Westerhof <Ce...@decebal.nl> writes:


> set a [expr {${m} ** 2 - ${n} ** 2}]
> set b [expr {2 * ${m} * ${n}}]
> set c [expr {${m} ** 2 + ${n} ** 2}]

By the way, none of the variable references you've been showing lately
have needed braces. Maybe you just like using them to always be safe
(you can't enjoy typing them!), but I find things more legible without,
especially in expressions or other places with plenty of braces.

set a [expr {$m ** 2 - $n ** 2}]
set b [expr {2 * $m * $n}]
set c [expr {$m ** 2 + $n ** 2}]

--
Donald Arseneau as...@triumf.ca
0 new messages