The bizarre world of typeof()

Don nospam at nospam.com
Mon Oct 26 06:54:29 PDT 2009


Lars T. Kyllingstad wrote:
> Don wrote:
>> I'm trying to make sense of the rules for 'typeof'. It's difficult 
>> because DMD's behaviour is so different to the spec. Here's four 
>> simple cases.
>>
>> // This doesn't compile on D1.
>> //alias typeof(int*int) Alias1;
>>
>> // This compiles in D1, but not in D2.
>> alias int Int;
>> alias typeof(Int*Int) Alias2;
>>
>> // Yet this DOES compile on D2 !
>> typeof(T*U) foo(T, U)(T x, U y) { return x*y; }
>> alias typeof(foo(Int, Int)) Alias3;
>>
>> // And this fails on both D1 and D2, with a dreadful error message.
>> //alias typeof(foo(int)) Alias4;
>>
>> I can't see anything in the spec to say why ANY of these examples 
>> should compile. Yet, the existing template constraints features relies 
>> on the Alias3 case.
> 
> 
> Here are a few more:
> 
>     class Foo { real bar() { return 1.0; } }
>     Foo foo = new Foo;
> 
>     // Passes, but should fail.
>     static assert (is (typeof(foo.bar) == function));
> 
>     // Passes, as expected.
>     static assert (is (typeof(&foo.bar) == delegate));
> 
>     // Passes, but should fail. This is similar to Don's examples.
>     static assert (is (typeof(Foo.bar) == function));
> 
>     // This one fails with the following hilarious message:
>     // Error: static assert  (is(real function() == function)) is false
>     static assert (is (typeof(&Foo.bar) == function));
> 
> I have no idea why typeof(&Foo.bar) even works, but it does. &Foo is 
> completely meaningless.

Dot has higher precedence than &, so it means &(Foo.bar), not (&Foo).bar.

The static assert fails because "real function()" is a *function 
pointer*, but is(xxx == function) tests to see if xxx is a *function*, 
not a *function pointer*.

So this passes:
void function () goo;
static assert( is (typeof(*goo) == function));

It's pretty awful that that in "is(real function() == function)", the 
keyword 'function' has two contradictory meanings in the same 
expression. And the spec never says what "function type" is.

>> I can see two ways forward:
>> (1) enforce the existing spec. Make all uses of types as expressions 
>> into a bug. This will break a lot of existing code, including several 
>> in the DMD test suite!
>> You'd generally need to include a .init whenever using a type inside a 
>> typeof(). This would make some code a lot uglier.
>> I'm also not sure what happens with alias parameters. (If A is an 
>> alias to a type, then typeof(A*A) should be changed to 
>> typeof(A.init*A.init); but if it's an alias to a variable, it should 
>> remain as typeof(A*A)).
>>
>> (2) Define that, inside a typeof() expression, any type T is 
>> translated into T.init. The syntax for typeof() would need to be 
>> changed, in order to allow the case 'alias1'.
>>
>> Note, however, that in both cases there's no such thing as .init for 
>> tuples; it might need to be added.
>>
>> Behaviour (2) is probably more convenient, behaviour (1) is easier to 
>> justify. But I think the existing behaviour of typeof() doesn't make 
>> much sense.
> 
> I vote for (1). There should be as few "special cases" in the language 
> as possible.
> 
> -Lars



More information about the Digitalmars-d mailing list