www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Understand signature of opOpAssign in std/complex.d

reply =?UTF-8?B?UmVuw6k=?= Heldmaier <rene.heldmaier gmail.com> writes:
Hi,
i'm currently implementing a dual number datatype. Dual numbers 
are very similar to complex numbers, but instead i (i^2 = -1) you 
have epsilon (epsilon^2 = 0).
This sounds strange but it is really useful for something called 
"automatic derivation". I will probably explain it in more detail 
when i'm ready to publish it as a dub package...

Because of the similarity to complex numbers i looked at how they 
are implemented in std/complex.d, to learn from how it is done 
there.

I came across a function signature which i don't understand:

ref Complex opOpAssign(string op, C)(const C z)
         if ((op == "+" || op == "-") && is(C R == Complex!R))

The part i don't understand is "is(C R == Complex!R)".
What does that mean?
Nov 09 2019
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Saturday, 9 November 2019 at 12:30:46 UTC, René Heldmaier 
wrote:
 The part i don't understand is "is(C R == Complex!R)".
 What does that mean?
That's checking the if the template argument C is a case of Complex!R, while at the same time declaring a symbol R to hold the inner type. So let's say we passed it a Complex!int. In that case, C is Complex!int, and then the new name, R, is declared to be `int`. (though the name R in here is only valid inside that one expression because it is in the constraint... if you need to use it inside the function body, you will need to do it again: void foo(C)(C c) if(is(C R == Complex!R)) { static if(is(C R == Complex!R)) // gotta redeclare in this scope pragma(msg, R); // will print the type passed now } Can read more here: https://dlang.org/spec/expression.html#IsExpression I just like to think of it as a variable declaration pattern. A normal variable is declared int a = 0; where it goes `type name OPERATOR initializer` so the is(C R == Y) is kinda similar: the existing type is C, the new name is R, then the == Y is the initializer. still magic syntax but it helps remember the order at least. And then the Y is like writing out the variable with placeholders.
Nov 09 2019
next sibling parent =?UTF-8?B?UmVuw6k=?= Heldmaier <rene.heldmaier gmail.com> writes:
On Saturday, 9 November 2019 at 13:26:12 UTC, Adam D. Ruppe wrote:
 That's checking the if the template argument C is a case of 
 Complex!R, while at the same time declaring a symbol R to hold 
 the inner type.
I got it. Thank you very much ;)
Nov 09 2019
prev sibling parent reply Q. Schroll <qs.il.paperinik gmail.com> writes:
On Saturday, 9 November 2019 at 13:26:12 UTC, Adam D. Ruppe wrote:
 On Saturday, 9 November 2019 at 12:30:46 UTC, René Heldmaier 
 wrote:
 The part i don't understand is "is(C R == Complex!R)".
 What does that mean?
That's checking the if the template argument C is a case of Complex!R, while at the same time declaring a symbol R to hold the inner type.
What's the difference of is(C R == Complex!R) to is(C == Complex!R, R) then?
Nov 11 2019
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Monday, 11 November 2019 at 16:59:57 UTC, Q. Schroll wrote:
 What's the difference of
     is(C R == Complex!R)
 to
     is(C == Complex!R, R)
 then?
Nothing, they do the same thing. (I'm of the opinion that the first one should actually be illegal - I thought it was until I checked for this thread - since it is weird. The general rule is placeholders need to be defined after the pattern, not before. The `C R == X` thing usually defines R to be an alias of something that already exists - maybe C itself, maybe a specialization of X like __parameters - but meh it did work here so weird and as far as I can tell they are identical.)
Nov 11 2019