CommonType and non-built-in types

monarch_dodra monarchdodra at gmail.com
Tue Oct 1 04:15:47 PDT 2013


On Tuesday, 1 October 2013 at 10:50:39 UTC, Joseph Rushton 
Wakeling wrote:
> Hello all,
>
> In the course of examining std.rational I've had to take a look 
> inside std.traits.CommonType, and I'm hoping people can help me 
> to understand some fine details which I'm currently unsure of.
>
> The essence of the CommonType template is simple:
>
>     * If it is passed no arguments, the common type is void.
>
>     * If it is passed one argument, the common type is the type 
> of that
>       argument.
>
>     * If it is passed more than one argument, it looks for the 
> common type U
>       between the first 2 arguments.  If it finds it, then it 
> returns the
>       common type of U and the remaining arguments (in other 
> words, it
>       recursively identifies the common types of successive 
> arguments until
>       none are left).
>
>     * If the first 2 arguments can't be implicitly converted, 
> it returns void.
>
> A consequence of this is that CommonType will not necessarily 
> work nicely with many non-built-in types.  For example, the 
> common type of BigInt and int is void, even though in principle 
> it should be possible to convert an int to a BigInt.  It's this 
> that is particularly of concern to me.
>
> Anyway, to concrete questions.
>
> (1) Can someone please explain to me _in detail_ the mechanics 
> of the code which identifies whether the first 2 template 
> arguments have a common type?
>
> I understand what it does, but not why/how it does it, if you 
> get me :-)
>
>     static if (is(typeof(true ? T[0].init : T[1].init) U))
>     {
>         alias CommonType!(U, T[2 .. $]) CommonType;
>     }
>
> (2) Same code -- why is it only necessary to check T[0].init : 
> T[1].init and not vice versa?  (Yes, you can tell I don't 
> really understand the : operator properly:-)
>
> (3) What would one have to implement in a library-defined type 
> to enable T[0].init : T[1].init to evaluate to true?  For 
> example, to enable int and BigInt to be compatible?
>
> (4) Is there a good reason why there _shouldn't_ be a 
> CommonType of (say) int and BigInt?
>
> I'm sure I'll think up more questions, but this seems enough to 
> be going on with ... :-)
>
> Thanks & best wishes,
>
>     -- Joe

The code basically uses operator ?: which is basically:
auto oeprator(T1, T2)(bool cont, T1 lhs, T2 rhs)
{
     if (cond)
         return lhs;
     else
         return rhs;
}
By using the operator's return type, you get, basically, what the 
compiler believes is the "common type" that you'd get from either 
a T1, or a T2.

Back to the code:
static if (is(typeof(true ? T[0].init : T[1].init) U))

This basically checks if ternary compiles, and if it does, 
"assigns" the return type to U, after which, the common type 
becomes U.

> (2) Same code -- why is it only necessary to check T[0].init : 
> T[1].init and not vice versa?  (Yes, you can tell I don't 
> really understand the : operator properly:-)

Order makes no difference.

> (3) What would one have to implement in a library-defined type 
> to enable T[0].init : T[1].init to evaluate to true?

I think you are reading the code wrong, it's not "T[0].init : 
T[1].init" that evaluates to "true". It's the argument of the 
ternary operator. "true" is just a dummy placeholder. What this 
code is checking is that "condition ? T[0].init : T[1].init" 
compiles at all.

> (4) Is there a good reason why there _shouldn't_ be a 
> CommonType of (say) int and BigInt?

Well, given that D doesn't allow implicit construction, and that 
the entire point of "CommonType" (AFAIK) is to check the 
*implicit* common type, it would be a little difficult.


More information about the Digitalmars-d-learn mailing list