Where does "U" in Rebindable.Rebindable come from?

Simen Kjærås simen.kjaras at gmail.com
Fri Mar 30 08:13:25 PDT 2012


On Fri, 30 Mar 2012 15:03:49 +0200, simendsjo <simendsjo at gmail.com> wrote:

> On Fri, 30 Mar 2012 01:09:06 +0200, Simen Kjærås  
> <simen.kjaras at gmail.com> wrote:
>
>> On Thu, 29 Mar 2012 22:15:41 +0200, simendsjo <simendsjo at gmail.com>  
>> wrote:
>>
>>> If you look at the struct, it uses the type U in, among others, the  
>>> union.
>>>
>>> The only place I could see U referenced is in the first static if, but  
>>> I cannot recreate this behavior:
>>> void main() {
>>>      static if(is(int X == const(U), U))
>>
>> Ah, the magic of isExpressions...
>>
>> What happens here is the isExpression asks 'if X is an int, does it
>> match the pattern const(U), where U is some type?'
>>
>> Of course, there is no U for which const(U) == int, so the isExpresion
>> returns false, and your static assert triggers.
>>
>>
>>>     static if (!is(T X == const(U), U) && !is(T X == immutable(U), U))
>>
>> Again, 'is there a U such that const(U) == T?', then the same for
>> immutable(U). In other words - 'is T mutable?'.
>>
>> The reason the U is there is to explain to the compiler that we're
>> talking about this specific U, not some other U that may be defined
>> elsewhere in the program.
>>
>> The same pattern is used in std.typecons.isTuple:
>>
>> template isTuple(T)
>> {
>>      static if (is(Unqual!T Unused : Tuple!Specs, Specs...))
>>      {
>>          enum isTuple = true;
>>      }
>>      else
>>      {
>>          enum isTuple = false;
>>      }
>> }
>>
>> It can also be extended to other templates:
>>
>> struct Foo() {}
>> struct Foo(int n) {}
>> struct Foo(T) {}
>>
>> template FooType(T) {
>>      static if (is(Unqual!T Unused : Foo!())) {
>>          enum FooType = "Type 1";
>>      } else static if (is(Unqual!T Unused : Foo!n, int n)) {
>>          enum FooType = "Type 2";
>>      } else static if (is(Unqual!T Unused : Foo!U, U)) {
>>          enum FooType = "Type 3";
>>      } else {
>>          enum FooType = "No Foo!";
>>      }
>> }
>>
>>
>> Hope this helps.
>
> Look at the Rebindable example again. What I don't understand is how U  
> can be defined in the else block.
> Like your example here. "Unused" isn't defined in the else block,  
> right..?

Indeed. The thing is - U is basically *set* by the isExpression. It says
'yes, there is such a U, so I'll add it to the local scope.'. This means
that U will be set for the entire scope within which the static if
exists.

Due to the way the criteria are phrased, U is defined when the criteria
are not met, and as such are defined in the else clause instead of the
if clause.


{ // Outer scope starts here.
   static if ( !is( const(int) t == const(U), U ) ) {
     // isExpression returned false, so U is undefined
   } else {
     // But here it is defined, because we're still in the same,
     // broader scope.
   }
}
// And here it's no longer defined.

Was that any better? I admit I didn't understand it at first either, but
then I remembered that static if does not introduce a new scope. That
helped.


More information about the Digitalmars-d-learn mailing list