The bizarre world of typeof()

Lars T. Kyllingstad public at kyllingen.NOSPAMnet
Mon Oct 26 03:41:23 PDT 2009


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.


> 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