www.digitalmars.com         C & C++   DMDScript  

D - The 'interchange' operator

reply bodan k.ro writes:
I just heard about D, and I read that new features can still be added, so I
thought I'd suggest an 'interchange' operator (for example, ><), that exhanges
the two operands, such that a><b is equivalent to aux=a; a=b; b=aux. It seemed
useful to me on many ocasions, it is very easy to implement, and it makes code
simpler to write and read. It is also quicker (it elimnates the need for aux
and, for references, it can be implemented with two xor's). So, why isn't there
one yet?

Anyway, I've been looking for a few minutes and couldn't find any place better
to send this suggestion, so if you guys now where it should go, please forward
it there.
Jan 14 2003
parent reply "Scott Pigman" <scottpig1 attbi.com> writes:
a couple of us in another thread have stated a desire for a tuple
construct in order to allow multiple return values from a function.  the
reason i mention it is that such a construct would also allow you to
exchange values w/out adding a new operator:

	a,b = b,a

btw, this is blatently plagerized from python (which may well have stole
it from an earlier source ;-)

scott

On Tue, 14 Jan 2003 12:19:44 +0000, boda wrote:

 I just heard about D, and I read that new features can still be added,
 so I thought I'd suggest an 'interchange' operator (for example, ><),
 that exhanges the two operands, such that a><b is equivalent to aux=a;
 a=b; b=aux. It seemed useful to me on many ocasions, it is very easy to
 implement, and it makes code simpler to write and read. It is also
 quicker (it elimnates the need for aux and, for references, it can be
 implemented with two xor's). So, why isn't there one yet?
 
 Anyway, I've been looking for a few minutes and couldn't find any place
 better to send this suggestion, so if you guys now where it should go,
 please forward it there.

Jan 19 2003
next sibling parent Russell Lewis <spamhole-2001-07-16 deming-os.org> writes:
Scott Pigman wrote:
 a couple of us in another thread have stated a desire for a tuple
 construct in order to allow multiple return values from a function.  the
 reason i mention it is that such a construct would also allow you to
 exchange values w/out adding a new operator:
 
 	a,b = b,a
 
 btw, this is blatently plagerized from python (which may well have stole
 it from an earlier source ;-)

I believe that you can do something like that in perl with lists...
Jan 21 2003
prev sibling next sibling parent reply Antti Sykari <jsykari gamma.hut.fi> writes:
"Scott Pigman" <scottpig1 attbi.com> writes:

 a couple of us in another thread have stated a desire for a tuple
 construct in order to allow multiple return values from a function.  the
 reason i mention it is that such a construct would also allow you to
 exchange values w/out adding a new operator:

 	a,b = b,a

While this form might look elegant, it - hides the creation of a temporary value and makes the compiler responsible for creating one so that it would work properly - forces you to write the expressions a and b twice (-> redundancy) - is actually longer to type than "swap(a,b)" -Antti
Jan 22 2003
parent reply "Scott Pigman" <scottpig some.where.com> writes:
On Wed, 22 Jan 2003 11:46:51 +0200, Antti Sykari wrote:

 "Scott Pigman" <scottpig1 attbi.com> writes:
 
 a couple of us in another thread have stated a desire for a tuple
 construct in order to allow multiple return values from a function. 
 the reason i mention it is that such a construct would also allow you
 to exchange values w/out adding a new operator:

 	a,b = b,a

While this form might look elegant, it - hides the creation of a temporary value and makes the compiler responsible for creating one so that it would work properly - forces you to write the expressions a and b twice (-> redundancy) - is actually longer to type than "swap(a,b)" -Antti

the original post was a request for an interchange operator, which to the best of my knowledge would also create a temporary variable that the compiler would be responsible for. i was just pointing out that the tuple idea brought up elsewhere would eliminate the need for a special operator used just for swapping. as for swap(a,b) - are functions pass-by-reference or pass-by-value? and couldn't swap(a,b){ a,b = b,a;} be a possible implementation of it <g>? -s
Jan 22 2003
parent reply "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> writes:
"Scott Pigman" <scottpig some.where.com> escreveu na mensagem
news:b0mbtg$17nr$1 digitaldaemon.com...
 On Wed, 22 Jan 2003 11:46:51 +0200, Antti Sykari wrote:

 "Scott Pigman" <scottpig1 attbi.com> writes:

 a couple of us in another thread have stated a desire for a tuple
 construct in order to allow multiple return values from a function.
 the reason i mention it is that such a construct would also allow you
 to exchange values w/out adding a new operator:

 a,b = b,a

While this form might look elegant, it - hides the creation of a temporary value and makes the compiler responsible for creating one so that it would work properly - forces you to write the expressions a and b twice (-> redundancy) - is actually longer to type than "swap(a,b)" -Antti

the original post was a request for an interchange operator, which to the best of my knowledge would also create a temporary variable that the compiler would be responsible for. i was just pointing out that the tuple idea brought up elsewhere would eliminate the need for a special operator used just for swapping. as for swap(a,b) - are functions pass-by-reference or pass-by-value? and couldn't swap(a,b){ a,b = b,a;} be a possible implementation of it <g>? -s

Given ints a and b, one can swap them without using a temporary variable: b = a + b; a = b - a; b = b - a; The same thing goes to anything else, because you just need to cast them back and forth to ints. So an "interchange" operator can be defined without using temporary variables. --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.443 / Virus Database: 248 - Release Date: 10/1/2003
Jan 22 2003
next sibling parent reply Ilya Minkov <midiclub 8ung.at> writes:
Daniel Yokomiso wrote:

 Given ints a and b, one can swap them without using a temporary variable:
 
 b = a + b;
 a = b - a;
 b = b - a;

What's the sanity of this? This code does the following: - load a, b into registers; - perform stoopid math; - save registers into variables. Note, if the variables are already in the registers, they can be exchanged with 1 asm command. Or not exchanged at all, but accounted for at further operation and when saving them later. If both are in memory, they have to be simply loaded and saved, and the rest is not requiered. Obviously, there is no C operation which maps to the exchange of two variables in a normal manner, but when you use a temporary even a simple compiler (LCC!) detects it and makes the most optimal decision, which mathematical wizardry is not. However, it would be sweet not to specify the variable explicitly. Or to be able to write an exchange elegantly and legibly in one line using tuples, which also have a number of other uses. -i.
Jan 22 2003
next sibling parent reply "Mike Wynn" <mike.wynn l8night.co.uk> writes:
 Given ints a and b, one can swap them without using a temporary


 b = a + b;
 a = b - a;
 b = b - a;

What's the sanity of this? This code does the following: - load a, b into registers; - perform stoopid math; - save registers into variables.

a = a ^ b; b = a ^ b; a = a ^ b; it's use is to swap to cpu registers without a 3rd or a store+load but otherwise its pointless most cpus have a swap op these days x86 has reg, mem exchange anyway (though it does lock) Arm has reg, [reg] exchange I'm sure PPC and MIPS have similar.
Jan 22 2003
next sibling parent reply Ilya Minkov <midiclub 8ung.at> writes:
Mike Wynn wrote:
 the usual form is
 a = a ^ b;
 b = a ^ b;
 a = a ^ b;

This math is not better, IMO. Same 3 operations, all of them atomic (1 m-op), and execute in any pipe. So on intel, and all the others shouldn't be very different. And when doing such things, originality matters more, since the *usual* way would be to swap registers with a dedicated command!
Jan 22 2003
parent "Mike Wynn" <mike.wynn l8night.co.uk> writes:
"Ilya Minkov" <midiclub 8ung.at> wrote in message
news:b0n2c8$1m2s$1 digitaldaemon.com...
 Mike Wynn wrote:
 the usual form is
 a = a ^ b;
 b = a ^ b;
 a = a ^ b;

This math is not better, IMO. Same 3 operations, all of them atomic (1 m-op), and execute in any pipe. So on intel, and all the others shouldn't be very different.

this maths is a lot better, 1, it's bitwise so carry flag does not effect the op and the op does not effect the carry. and 2 its the same op rather 3 times, due to the self inverse behaviour of xor.
 And when doing such things, originality matters more, since the *usual*
 way would be to swap registers with a dedicated command!

not I usually swap that way I totally agree (please read my comments) BUT most CPU's that have swap/exchange ONLY have reg, [reg] not reg, reg and in the old days there where no exchange op's and less registers, no pipelines, only one alu etc etc etc. mov r2, r1; mov r1, r0; mov r0, r2; <- 3 op's uses 3 regs xor r1, r1, r0; xor r0, r1, r0; xor r1, r1, r0 <- 3 ops uses 2 regs that's the only reason, apart from being a mathmatical curiosity xchg on the x86 asserts the lock, which stall things so it is avoided unless needed and how often do you need to swap 2 values ? I've got more code that uses rotates `a = ((b<<c)|(b>>-c));` than used swaps
Jan 22 2003
prev sibling parent Scott Wood <scott buserror.net> writes:
On Wed, 22 Jan 2003 20:43:02 -0000, Mike Wynn <mike.wynn l8night.co.uk> wrote:
 it's use is to swap to cpu registers without a 3rd or a store+load
 but otherwise its pointless most cpus have a swap op these days
 x86 has reg, mem exchange anyway (though it does lock)
 Arm has reg, [reg] exchange

Which you would never want to use unless you need atomicity (or perhaps if optimizing for space is your primary concern); otherwise, it's faster to do it manually. Plus, on some ARMs, SWP bypasses the cache. In fact, on non-super-scalar chips such as most if not all ARMs, the math tricks might actually be the best way to do the exchange, since you never have to spill a register for a temporary, and the chained result dependencies aren't an issue. It's three instructions either way...
 I'm sure PPC and MIPS have similar.

They don't; they use a load locked/store conditional mechanism to achieve atomicity. They also have enough registers that using a third is unlikely to be a problem. :-) -Scott
Jan 22 2003
prev sibling parent reply "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> writes:
"Ilya Minkov" <midiclub 8ung.at> escreveu na mensagem
news:b0mrht$1i24$1 digitaldaemon.com...
 Daniel Yokomiso wrote:

 Given ints a and b, one can swap them without using a temporary


 b = a + b;
 a = b - a;
 b = b - a;

What's the sanity of this? This code does the following: - load a, b into registers; - perform stoopid math; - save registers into variables.

It's not intended to be sane, fast or easy to understand, but it doesn't use ANY temporary variables. It's just to prove that it can be written without extra storage. I'm not saying that D should do this, or that this is good programming. --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.443 / Virus Database: 248 - Release Date: 10/1/2003
Jan 22 2003
parent reply "Sean L. Palmer" <seanpalmer directvinternet.com> writes:
What I'm saying is that Joe Programmer should not have to implement this
*crap*, for any type, let alone all types.  Swap is a basic intrinsic
operation and should be defined by the language for everything that's
assignable.  Then the compiler can generate whatever wierd code is needed to
perform the swap optimally for the platform.   Think semantics, not
implementation.

Same goes for min, and max.  If you have to have the compiler "figure out
what you meant" after the fact, it can't be depended upon.  Better to just
tell it exactly what you intend.

Hell, C even has abs() (and labs(), and fabs()) and yet hordes of code I've
seen has stupid if (f < 0) f = -f; or (f<0 ? -f : f) crap gumming up the
works.  That might be a counterargument, in fact.  ;)  But you should be
able to trust the compiler to generate good code if you call abs() or
fabs();  I wouldn't expect a compiler to turn (f < 0 ? -f : f) into
something that has no branches.  But if it does, great.  I'm just not gonna
depend on it.

There should be a certain baseline for functionality;  all machines either
support swap, min, max, abs natively, or have the mechanisms to implement
them.  That's fundamental computing.

Look at the mess Windows made with MIN and MAX #defines (actually it also
#define's min and max as well, confounding ISO std::C++)

It would pay to do a thorough job of covering the fundamentals, up front.

Rotate is also a good candidate.  It's in C library for most platforms
anyway even if it's not standard.  As someone pointed out, it can be
implemented easily with two shifts and an or, *if* the cpu happens to lack
such an operation.  I think that would be rare.  Anyone that can implement a
compiler can do code generation for rotate, no problem.  It wouldn't burden
implementors one bit.  It would be a useful addition to the D language.

Any other common low level stuff that isn't in D?

clamp (just a wrapper around a min and max combo).
test if in range.
Inexact comparison for floats (f1 ?= f2  generates  abs(f1 - f2) < epsilon,
though specifying what epsilon should be would be an issue).
div+mod combination
converting from float to int with various forms of rounding, at bare minimum
truncate and round nearest, which are implementable in terms of each other.
power function  x**y  or  pow(x,y)

I'm running out of them.  There aren't that many.

The upside to this is that if new operators are added for these, that's just
that many more operators we can overload later.  ;)

Sean

"Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> wrote in message
news:b0mvt1$1kjh$1 digitaldaemon.com...
 It's not intended to be sane, fast or easy to understand, but it doesn't

 ANY temporary variables. It's just to prove that it can be written without
 extra storage. I'm not saying that D should do this, or that this is good
 programming.

Jan 22 2003
parent reply "Carlos Santander B." <carlos8294 msn.com> writes:
"Sean L. Palmer" <seanpalmer directvinternet.com> escribiσ en el mensaje
news:b0o345$27ls$1 digitaldaemon.com...
| Hell, C even has abs() (and labs(), and fabs()) and yet hordes of code
I've
| seen has stupid if (f < 0) f = -f; or (f<0 ? -f : f) crap gumming up the

Actually, that brings me to this question: if I import, let's say, c.stdio
and I only use printf(), does dmd still compile the other functions? I know
that if I don't use anything from the module, dmd ignores it, but what about
specific things?
The reasoning behind doing what you said is the same: why would I import
(include, in this case) sqrt, sin, cos, etc., when I only need abs?

—————————————————————————
Carlos Santander
http://carlos3.netfirms.com/
"Sean L. Palmer" <seanpalmer directvinternet.com> escribiσ en el mensaje
news:b0o345$27ls$1 digitaldaemon.com...
| Hell, C even has abs() (and labs(), and fabs()) and yet hordes of code
I've
| seen has stupid if (f < 0) f = -f; or (f<0 ? -f : f) crap gumming up the

Actually, that brings me to this question: if I import, let's say, c.stdio
and I only use printf(), does dmd still compile the other functions? I know
that if I don't use anything from the module, dmd ignores it, but what about
specific things?
The reasoning behind doing what you said is the same: why would I import
(include, in this case) sqrt, sin, cos, etc., when I only need abs?

—————————————————————————
Carlos Santander
http://carlos3.netfirms.com/
Jan 23 2003
parent Russell Lewis <spamhole-2001-07-16 deming-os.org> writes:
Carlos Santander B. wrote:
 "Sean L. Palmer" <seanpalmer directvinternet.com> escribiσ en el mensaje
 news:b0o345$27ls$1 digitaldaemon.com...
 | Hell, C even has abs() (and labs(), and fabs()) and yet hordes of code
 I've
 | seen has stupid if (f < 0) f = -f; or (f<0 ? -f : f) crap gumming up the
 
 Actually, that brings me to this question: if I import, let's say, c.stdio
 and I only use printf(), does dmd still compile the other functions? I know
 that if I don't use anything from the module, dmd ignores it, but what about
 specific things?
 The reasoning behind doing what you said is the same: why would I import
 (include, in this case) sqrt, sin, cos, etc., when I only need abs?

Importing a library does not cause the functions of that library to be included in your binary - unless, of course, the compiler chooses to inline the function. Instead, each function exists in the .o (or library file) that corresponds with where the function was defined.
Jan 23 2003
prev sibling next sibling parent "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> writes:
"Antti Sykari" <jsykari gamma.hut.fi> escreveu na mensagem
news:86u1g0dfyu.fsf hoastest1-8c.hoasnet.inet.fi...
 "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> writes:
 Given ints a and b, one can swap them without using a temporary


 b = a + b;
 a = b - a;
 b = b - a;

Or, if you want to avoid the tedious and error-prone arithmetic operations, you can use the classic alternative: a ^= b; b ^= a; a ^= b; Enough with jokes... To be serious, I thought about the tuples a while and decided that probably it would be the best to implement tuple assignments as a following translation: // assume Type1 t1, Type2 t2, ..., TypeN tN; t1, t2, ..., tN = expr1, expr2, ..., exprN; would be translated to Type1 tmp1; Type2 tmp2; ...; TypeN tmpN; tmp1 = expr1; ...; tmpN = exprN; t1 = tmp1; ...; tN = exprN; So that even "a, b = b, a" would work intuitively and unnecessary temporaries would be removed by the compiler. Tuples don't come free. With the above-mentioned syntax they might cause slight parsing problems. Most visibly, they might would make the comma operator unusable because it would be indistinguishable from the tuples. So the alternatives seem to be "keep the comma operator and use a different syntax for tuples", "introduce special cases where comma operator can be used in tuples (for example inside parens)", and "change the comma operator to a different form or otherwise render it unusable". Antti

Hi, This work for this particular case of tuple construction/deconstruction, but usually people will use that with functions, like: ComparableCollection numbers = ...; int min, max = numbers.bounds(); So generic tuples must work like structs, accessing defined stack areas (nothing forbids the compiler to generate code like what you did for this special case). Of course all this talk about tuples would make in/out/inout kind of obsolete. About tuple syntax, we can force people using parenthesis in tuples, so it should look like: (a,b) = (b,a); And defined method call based on tuple passing, so calling "foo(a,b,c);" is giving foo the tuple (a,b,c). Empty tuples would come free, and single element tuples too. With this in mind we could say that every single value is equivalent to a single element tuple, so we can still use parenthesis to reorder expressions, but it'll just create single element tuples. That could render the comma operator useless. It's semantics could be emulated by a simple (but strange) rule for tuples: tuples are pruned from left to right to fit in their targets: int a = (1,2,3,4); // a is 4 int (a,b) = (1,2,3,4); // a is 3, b is 4 int (a,b,c) = (1,2,3,4); // a is 2, b is 3, c is 4 int (a,b,c,d) = (1,2,3,4); // a is 1, b is 2, c is 3, d is 4 But I think this is most likely to cause bugs. There is any idiom that the comma operator (as is stands today) makes clearer? As a side note if we unify this tuple construction/deconstruction rules with function call we can end with functional languages syntax, so: omparableCollection numbers = ...; Range bounds = new Range numbers.bounds(); // function application or we can force the parenthesis: Range bounds = new Range(numbers.bounds()); Which can also lead to unmaintainable code. Also with single value = single element tuple paradigm, we'll flatten more tuples than usual: ((((1))),((2,3),((4))),(5)) // I feel lispish today ;-) will become: (1,((2,3),4),5) Which may be a good thing. Or not ;-) Best regards, Daniel Yokomiso. "The consumer is not an idiot, she is your wife." - David Ogilvy, founder of Ogilvy & Mather --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.443 / Virus Database: 248 - Release Date: 10/1/2003
Jan 22 2003
prev sibling parent "Walter" <walter digitalmars.com> writes:
"Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> wrote in message
news:b0mq5b$1h7f$1 digitaldaemon.com...
 Given ints a and b, one can swap them without using a temporary variable:

 b = a + b;
 a = b - a;
 b = b - a;

If one did this as a generic operation on types, it would screw up the garbage collector. This is because if the thread was halted in the middle of such a calculation to check for pointers, one of the pointers would be scrambled, and would be missed. A generic implementation would have to use temporaries.
Feb 07 2003
prev sibling next sibling parent Antti Sykari <jsykari gamma.hut.fi> writes:
"Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> writes:
 Given ints a and b, one can swap them without using a temporary variable:

 b = a + b;
 a = b - a;
 b = b - a;

Or, if you want to avoid the tedious and error-prone arithmetic operations, you can use the classic alternative: a ^= b; b ^= a; a ^= b; Enough with jokes... To be serious, I thought about the tuples a while and decided that probably it would be the best to implement tuple assignments as a following translation: // assume Type1 t1, Type2 t2, ..., TypeN tN; t1, t2, ..., tN = expr1, expr2, ..., exprN; would be translated to Type1 tmp1; Type2 tmp2; ...; TypeN tmpN; tmp1 = expr1; ...; tmpN = exprN; t1 = tmp1; ...; tN = exprN; So that even "a, b = b, a" would work intuitively and unnecessary temporaries would be removed by the compiler. Tuples don't come free. With the above-mentioned syntax they might cause slight parsing problems. Most visibly, they might would make the comma operator unusable because it would be indistinguishable from the tuples. So the alternatives seem to be "keep the comma operator and use a different syntax for tuples", "introduce special cases where comma operator can be used in tuples (for example inside parens)", and "change the comma operator to a different form or otherwise render it unusable". Antti
Jan 22 2003
prev sibling parent factory <tehdasX optushome.com.au> writes:
 On Tue, 14 Jan 2003 12:19:44 +0000, boda wrote:
 I just heard about D, and I read that new features can still be added,
 so I thought I'd suggest an 'interchange' operator (for example, ><),
 that exhanges the two operands, such that a><b is equivalent to aux=a;
 a=b; b=aux. It seemed useful to me on many ocasions, it is very easy to
 implement, and it makes code simpler to write and read. It is also
 quicker (it elimnates the need for aux and, for references, it can be
 implemented with two xor's). So, why isn't there one yet?


I might point out that in mathematics my experience is that mathematicians generally use max( 1,2..n ) style of notation and do not generally use a symbol. (although I have seen the traditional union symbol used as max in a web page on trinary arithmetic) I would argue that using mathematical symbols in languages is a positive thing, commonly accepted mathematical symbols are 'useful' (especially for numerical computing), and also tend to map well into code construction. So thus every language almost universally uses mathematical equality symbols (=,>,<, etc), and basic arithmetic symbols (+,-,*, etc). But for symbols that are not in ascii there is less agreement on how to represent them in a programming language. Most languages just use ascii symbols, or just use the names of the operation written out (ie. AND and OR). I say that we should reinstate the 'proper' mathematical symbols. Add U+00f7 for /, add U+2264 and U+2265 for <= and >=, etc. Cons: some mathematical symbols do not distinguish between binary and logical operations, ie U+2227 could be used for bitwise or logical AND. Oh and it's also a pain in the arse to type, well for most ppl who use latin keyboards. And bring in all the set notation too, with all the generics going on nowadays, those would be quite useful. Or at the very least, allow unicode to be in identifiers and allow the user to define binary operators, with the operator defined by a user keyword. Hmm dunno what the syntax would be for something like that, the standard way of writing binary operations only allows for overloading operators. hmm maybe something like: T operator xor( T, T ) Ohh, I've gone all C++.. - Factory
Jan 24 2003