Thread overview | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
August 20, 2013 Typeof woes | ||||
---|---|---|---|---|
| ||||
Given this short program:
class A {
int i;
//enum Smth { X };
void list () {
foreach( s; __traits(derivedMembers, typeof(this))) {
alias type = typeof(__traits(getMember, this, s));
}
}
}
void main () {
A a = new A();
a.list();
}
if I uncomment "enum" line I get compilation error: aa.d(8): Error: argument Smth to typeof is not an expression
So far it only happened with enums for me, but admittedly I didn't check all the possible types out there.
What's even more interesting it's just alias problem, the expression "typeof(__traits(getMember, this, s))" might be used eg. in static if even for enums.
Is this a bug or do I miss something (again)?
--
Marek Janukowicz
|
August 21, 2013 Re: Typeof woes | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marek Janukowicz | On Wed, Aug 21, 2013 at 01:42:11AM +0200, Marek Janukowicz wrote: > Given this short program: > > class A { > > int i; > //enum Smth { X }; > > void list () { > foreach( s; __traits(derivedMembers, typeof(this))) { > alias type = typeof(__traits(getMember, this, s)); > } > } > } > > void main () { > A a = new A(); > a.list(); > } > > if I uncomment "enum" line I get compilation error: aa.d(8): Error: argument Smth to typeof is not an expression > > So far it only happened with enums for me, but admittedly I didn't check all the possible types out there. The reason is that derivedMembers returns *all* members, including enum definitions, not just member variables and methods. So this includes 'Smth', and typeof(this.Smth) is invalid because this.Smth is already a type, so you can't apply typeof to it. To get around this, you will need to use static if, maybe something like this: void list() { // Warning: untested code foreach(s; __traits(derivedMembers, typeof(this))) { static if (is(typeof(__traits(getMember, this, s)) type)) { // here, 'type' is bound to the type of // the member. } } } This uses the is(X Y) form, where if X is a valid type, then it gets aliased to Y inside the static if block. (I have to admit I'm not that pleased with D's is-expressions due to their confusing syntax, but they do work and are quite a powerful tool to use once you understand them.) > What's even more interesting it's just alias problem, the expression > "typeof(__traits(getMember, this, s))" might be used eg. in static if > even for enums. > > Is this a bug or do I miss something (again)? [...] Are you sure about that? That doesn't sound right to me. T -- Lottery: tax on the stupid. -- Slashdotter |
August 21, 2013 Re: Typeof woes | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marek Janukowicz | typeof only accepts expressions, not types. Workaround: template myTypeOf(T...) if (T.length == 1) { static if (is(T)) alias myTypeOf = T; else alias myTypeOf = typeof(T); } |
August 21, 2013 Re: Typeof woes | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dicebot | On Wed, Aug 21, 2013 at 02:15:06AM +0200, Dicebot wrote: > typeof only accepts expressions, not types. > > Workaround: > > template myTypeOf(T...) > if (T.length == 1) > { > static if (is(T)) > alias myTypeOf = T; > else > alias myTypeOf = typeof(T); > } Clever. I may have to add this to my personal code library. :) T -- Everybody talks about it, but nobody does anything about it! -- Mark Twain |
August 21, 2013 Re: Typeof woes | ||||
---|---|---|---|---|
| ||||
On 8/21/13, H. S. Teoh <hsteoh@quickfur.ath.cx> wrote:
> and typeof(this.Smth) is invalid because this.Smth is already a type, so you can't apply typeof to it.
I am beginning to wonder if typeof(typeof(expr)) is worthy of an
error. Would we end up having any bugs if we were to allow typeof() to
work on types (IOW it would just alias itself to the type)?
I guess the only way to find out is to try it out in a compiler branch, but I'm genuinely curious.
|
August 21, 2013 Re: Typeof woes | ||||
---|---|---|---|---|
| ||||
On Wed, Aug 21, 2013 at 02:24:18AM +0200, Andrej Mitrovic wrote: > On 8/21/13, H. S. Teoh <hsteoh@quickfur.ath.cx> wrote: > > and typeof(this.Smth) is invalid because this.Smth is already a type, so you can't apply typeof to it. > > I am beginning to wonder if typeof(typeof(expr)) is worthy of an > error. Would we end up having any bugs if we were to allow typeof() to > work on types (IOW it would just alias itself to the type)? > > I guess the only way to find out is to try it out in a compiler branch, but I'm genuinely curious. Hmm. If typeof were idempotent on types, then it would provide nice closure properties (as in mathematical closure, not delegates) if we ever implement the proposed typetuple/std.typecons.Tuple unification from the other thread: typeof(tup(1,"a")) == tup(int,string) typeof(tup(int,"a")) == tup(int,string) typeof(tup(int,string)) == tup(int,string) This alleviates one of the nagging problems with mixed tuples that contain both types and expressions. Then the only left to do is to specify that a tuple can be used as a type only if it contains only types (IOW, if is(typeof(tup)==tup), a rather nice way to express it), and a tuple can be used as a value (assigned to variables, etc.) only if it contains only values. "Mixed" tuples can still be used as template arguments, and you can always apply typeof to them. T -- It's bad luck to be superstitious. -- YHL |
August 21, 2013 Re: Typeof woes | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On Wednesday, 21 August 2013 at 00:24:24 UTC, H. S. Teoh wrote:
> On Wed, Aug 21, 2013 at 02:15:06AM +0200, Dicebot wrote:
>> typeof only accepts expressions, not types.
>>
>> Workaround:
>>
>> template myTypeOf(T...)
>> if (T.length == 1)
>> {
>> static if (is(T))
>> alias myTypeOf = T;
>> else
>> alias myTypeOf = typeof(T);
>> }
>
> Clever. I may have to add this to my personal code library. :)
>
>
> T
It should have been T[0], not plain T, of course.
|
August 21, 2013 Re: Typeof woes | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | H. S. Teoh wrote: > On Wed, Aug 21, 2013 at 01:42:11AM +0200, Marek Janukowicz wrote: >> Given this short program: >> >> class A { >> >> int i; >> //enum Smth { X }; >> >> void list () { >> foreach( s; __traits(derivedMembers, typeof(this))) { >> alias type = typeof(__traits(getMember, this, s)); >> } >> } >> } >> >> void main () { >> A a = new A(); >> a.list(); >> } >> >> if I uncomment "enum" line I get compilation error: aa.d(8): Error: argument Smth to typeof is not an expression >> >> So far it only happened with enums for me, but admittedly I didn't check all the possible types out there. > > The reason is that derivedMembers returns *all* members, including enum definitions, not just member variables and methods. So this includes 'Smth', and typeof(this.Smth) is invalid because this.Smth is already a type, so you can't apply typeof to it. Yes, I do understand this, however the behavior indicated below (your last question and my code) got me really confused. > > To get around this, you will need to use static if, maybe something like this: > > void list() { > // Warning: untested code > foreach(s; __traits(derivedMembers, typeof(this))) { > static if (is(typeof(__traits(getMember, this, s)) type)) { > // here, 'type' is bound to the type of > // the member. > } > } > } > > This uses the is(X Y) form, where if X is a valid type, then it gets aliased to Y inside the static if block. (I have to admit I'm not that pleased with D's is-expressions due to their confusing syntax, but they do work and are quite a powerful tool to use once you understand them.) This code works, thank you. However, if I may share my newbie impression - current traits implementation looks not complete to me. What I want to do is to process those members that are of certain type - instead of a nice one- liner to identify those, I already need two and the first (the one you provided above) looks like a hack to me, because I have to check if some expression is valid. The whole issue (which to me looks like a quite standard metaprogramming task) already took me a few hours (and also some time of you and the other helpful guys) and I can't get rid of the impression either the docs are lacking or we could use some more traits. >> What's even more interesting it's just alias problem, the expression >> "typeof(__traits(getMember, this, s))" might be used eg. in static if >> even for enums. >> >> Is this a bug or do I miss something (again)? > [...] > > Are you sure about that? That doesn't sound right to me. Yes, I'm sure, here goes modified code: import std.stdio; class A { int a; enum Smth { A }; void list () { foreach( s; __traits(derivedMembers, typeof(this))) { //alias type = typeof(__traits(getMember, this, s)); static if (is (typeof(__traits(getMember, this, s)) == int)) { writefln ("%s is int", s ); } } } } void main () { A a = new A(); a.list(); } which outputs: a is int -- Marek Janukowicz |
August 21, 2013 Re: Typeof woes | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrej Mitrovic | On 2013-08-21 02:24, Andrej Mitrovic wrote: > I am beginning to wonder if typeof(typeof(expr)) is worthy of an > error. Would we end up having any bugs if we were to allow typeof() to > work on types (IOW it would just alias itself to the type)? > > I guess the only way to find out is to try it out in a compiler > branch, but I'm genuinely curious. As we have seen, not allowing typeof to accept types makes some generic code a bit more cumbersome to write. -- /Jacob Carlborg |
August 21, 2013 Re: Typeof woes | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrej Mitrovic | Andrej Mitrovic wrote: > On 8/21/13, H. S. Teoh <hsteoh@quickfur.ath.cx> wrote: >> and typeof(this.Smth) is invalid because this.Smth is already a type, so you can't apply typeof to it. > > I am beginning to wonder if typeof(typeof(expr)) is worthy of an > error. Would we end up having any bugs if we were to allow typeof() to > work on types (IOW it would just alias itself to the type)? It's not always considered an error, this code compiles fine (my guess is the "is" expression does some magic with its arguments): import std.stdio; class A { int a; enum Smth { A }; void list () { foreach( s; __traits(derivedMembers, typeof(this))) { static if (is (typeof(typeof(typeof(__traits(getMember, this, s)))) == int)) { writefln ("%s is int", s ); } } } } void main () { A a = new A(); a.list(); } -- Marek Janukowicz |
Copyright © 1999-2021 by the D Language Foundation