www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - check type

reply spir <denis.spir gmail.com> writes:
Hello,


What is the common idiom to check whether the type of a given element is wh=
at I expect?
Seems that
	typeof(e) =3D=3D Type
is refused by the compiler, for any reason? I get
	DeeMatch.d(237): Error: type string is not an expression
I'm using
	typeof(e).stringof =3D=3D "TypeName"=20
Is there a better solution?

Also, how to override a class's field so that it is accessed according actu=
al/runtime type? (Like method dispatch.)
	void method (SuperType x) {...access x.f...}
If I don't define f in SuperType, then I get a compiler error. If I do, the=
n SuperType.f is accessed, not the field on actual class of x.


Denis
-- -- -- -- -- -- --
vit esse estrany =E2=98=A3

spir.wikidot.com
Nov 06 2010
next sibling parent Adam Burton <adz21c gmail.com> writes:
spir wrote:

 Hello,
 
 
 What is the common idiom to check whether the type of a given element is
 what I expect? Seems that
 typeof(e) == Type
 is refused by the compiler, for any reason? I get
 DeeMatch.d(237): Error: type string is not an expression
 I'm using
 typeof(e).stringof == "TypeName"
 Is there a better solution?
 
 Also, how to override a class's field so that it is accessed according
 actual/runtime type? (Like method dispatch.) void method (SuperType x)
 {...access x.f...} If I don't define f in SuperType, then I get a compiler
 error. If I do, then SuperType.f is accessed, not the field on actual
 class of x.
 
 
 Denis
 -- -- -- -- -- -- --
 vit esse estrany ☣
 
 spir.wikidot.com
1. I believe typeof(e) will give you the type of "e" not the type of the object e is pointing too. So for example class A {} class B : A {} A a = new A(); B b = new B(); A a2 = new B(); typeof(a).stringof // A typeof(b).stringof // B typeof(a2).stringof // A I think there are methods in the Object class that gives you the name of the runtime type, but I have never checked. 2. When referencing SuperType you can only access the public members of SuperType (and its super/base types). In order to access the dervied class's members you need to reference it as the Derived. For example. class A { void a() {} } class B : A { void b() {} } class C : A { void c() {} } A d = new B(); d.a(); d.b(); // compile fail (cast(B) d).b(); (cast(C) d).c(); // fails at runtime I think as a rule the above is considered bad practice. If f does not exist in SuperType then you shouldn't be passing the function SuperType, you should be passing whatever type it is you are expecting that has f defined in it. The casts above get round it, but as I say, generally considered bad practice.
Nov 06 2010
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
spir:

 What is the common idiom to check whether the type of a given element is what
I expect?
 Seems that
 	typeof(e) == Type
 is refused by the compiler, for any reason? I get
 	DeeMatch.d(237): Error: type string is not an expression
I don't know why the language refuses a natural and more clean syntax like: if (typeof(x) == Type) {... I think it's to keep the compiler simple, clearly telling apart the compile-time phase that uses types (or CTFE) from the run-time that uses values. So you have to wrap it into a is(), often this is enough: if (is(typeof(x) == Type)) {... But look in the docs at the complex syntax of is() for the many other different ways to use it.
 Also, how to override a class's field so that it is accessed according
actual/runtime type? (Like method dispatch.)
This feature is named "double dispatch", and it's present in the object system named CLOS of CommonLisp, but unfortunately it's not present in D (or C++, Java, Python). Maybe the Scala language too has this feature. See: http://en.wikipedia.org/wiki/Double_dispatch http://en.wikipedia.org/wiki/Visitor_pattern The D language allows you to perform the dispatch only on the compile time type of the arguments (or the dynamic type of the "this"). This means that if you have to perform double dispatch in D/C++/Python, then you need to implement/simulate this feature manually. There are several ways to do it, see . In some situations if your program needs to use double dispatch heavily, then you may invent a string mixin to reduce somehow the boilerplate code.
 	void method (SuperType x) {...access x.f...}
 If I don't define f in SuperType, then I get a compiler error. If I do, then
SuperType.f is accessed, not the field on actual class of x.
D is a statically typed language, this means that in general the choices about types (this mean choice of code path or code generation by templates) are performed only at compile time. Despite languages like Java and D are statically typed, they allow a bit of dynamic typing, using the virtual table of the classes, and allowing run-time types of objects to differ from their compile-time type. But this bit of dynamic typing is limited and is not extended to double/multiple dispatch (on the other hand even very dynamic languages like Python lack double or multiple dispatch). Bye, bearophile
Nov 06 2010
parent reply spir <denis.spir gmail.com> writes:
On Sat, 06 Nov 2010 14:48:44 -0400
bearophile <bearophileHUGS lycos.com> wrote:

 spir:
=20
 What is the common idiom to check whether the type of a given element i=
s what I expect?
 Seems that
 	typeof(e) =3D=3D Type
 is refused by the compiler, for any reason? I get
 	DeeMatch.d(237): Error: type string is not an expression
=20 I don't know why the language refuses a natural and more clean syntax lik=
e:
 if (typeof(x) =3D=3D Type) {...
 I think it's to keep the compiler simple, clearly telling apart the compi=
le-time phase that uses types (or CTFE) from the run-time that uses values.
 So you have to wrap it into a is(), often this is enough:
 if (is(typeof(x) =3D=3D Type)) {...
 But look in the docs at the complex syntax of is() for the many other dif=
ferent ways to use it. Right. I looked at 'is' before, precisely. But there does not seem to be any direc= t idiom to test a variable's type. At least, the book TDPL does not show an= y. It shows only operations on types themselves (without any var). I'll che= ck your proposal =3D=3D> works, thanks!
 Also, how to override a class's field so that it is accessed according =
actual/runtime type? (Like method dispatch.)
=20
 This feature is named "double dispatch", and it's present in the object s=
ystem named CLOS of CommonLisp, but unfortunately it's not present in D (or= C++, Java, Python). Maybe the Scala language too has this feature. See:
 http://en.wikipedia.org/wiki/Double_dispatch
 http://en.wikipedia.org/wiki/Visitor_pattern
=20
 The D language allows you to perform the dispatch only on the compile tim=
e type of the arguments (or the dynamic type of the "this"). This means tha= t if you have to perform double dispatch in D/C++/Python, then you need to = implement/simulate this feature manually. There are several ways to do it, = see . In some situations if your program needs to use double dispatch heavi= ly, then you may invent a string mixin to reduce somehow the boilerplate co= de.
=20
=20
 	void method (SuperType x) {...access x.f...}
 If I don't define f in SuperType, then I get a compiler error. If I do,=
then SuperType.f is accessed, not the field on actual class of x.
=20
 D is a statically typed language, this means that in general the choices =
about types (this mean choice of code path or code generation by templates)= are performed only at compile time.
=20
 Despite languages like Java and D are statically typed, they allow a bit =
of dynamic typing, using the virtual table of the classes, and allowing run= -time types of objects to differ from their compile-time type. But this bit= of dynamic typing is limited and is not extended to double/multiple dispat= ch (on the other hand even very dynamic languages like Python lack double o= r multiple dispatch). Hem, I'm not sure it's double dispatch. What I mean works in many languges,= including python, Lua, and I guess OO langs of the Pascal family. Just thi= s: class SC { string f =3D "SC"; void show() {writeln(this.f);} } class C : SC { string f =3D "C"; } void main () { auto c =3D new C(); writeln(c.f) ; // OK, got "C" c.show() ; // expected "C", got "SC" =20 // below test for type if (is(typeof(c) =3D=3D C)) {writeln("type C");} else {writeln("type SC= ");} auto sc =3D new SC(); if (is(typeof(sc) =3D=3D C)) {writeln("type C");} else {writeln("type S= C");} } It's not double dispatch, I guess, but exactly the same dispatch on actual/= runtime type for fields as we have for methods. And it woeks for sure in py= thon (and many other languages): class SC: f =3D "SC" def show(self): print self.f class C (SC): f =3D "C" c =3D C() Well, actually, I don't need the feature anymore for the present use case, = as it was only to work around the above issue (had a "typename" field). But= I would still like to find a way of having fields accessed according actua= l type, or know for sure that it's impossible (and 'why" in option ;-). I guess it may be so because field access is resolved at compile-time, unli= ke method access. (Meaning so-to-say "zero-dispatch" for fields, while we h= ave single-dispatch for methods.) In dynamic languages, indeed, both are re= solved at runtime. But, if I'm right on this, the D way surely is a big gai= n in efficiency. Thank you, anyway, Denis -- -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Nov 06 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
spir:

 class SC {
     string f = "SC";
     void show() {writeln(this.f);}
 }
 class C : SC {
     string f = "C";
 }
 void main () {
     auto c = new C();
     writeln(c.f) ;  // OK, got "C"
     c.show() ;      // expected "C", got "SC"
     
     // below test for type
     if (is(typeof(c) == C)) {writeln("type C");} else {writeln("type SC");}
     auto sc = new SC();
     if (is(typeof(sc) == C)) {writeln("type C");} else {writeln("type SC");}
 }
Java acts as D here: http://ideone.com/LcAll http://ideone.com/AVFvI A D version that does as you desire: import std.stdio; class SC { string f_ = "SC"; property string f() { return f_; } void show() { writeln(this.f); } } class C : SC { string f_ = "C"; property override string f() { return f_; } } void main () { auto c = new C(); writeln(c.classinfo.name); auto sc = new SC(); writeln(sc.classinfo.name); writeln(c.f); // "C" c.show(); // "C" } Bye, bearophile
Nov 06 2010
parent reply spir <denis.spir gmail.com> writes:
On Sat, 06 Nov 2010 20:50:05 -0400
bearophile <bearophileHUGS lycos.com> wrote:

 spir:
=20
 class SC {
     string f =3D "SC";
     void show() {writeln(this.f);}
 }
 class C : SC {
     string f =3D "C";
 }
 void main () {
     auto c =3D new C();
     writeln(c.f) ;  // OK, got "C"
     c.show() ;      // expected "C", got "SC"
    =20
     // below test for type
     if (is(typeof(c) =3D=3D C)) {writeln("type C");} else {writeln("typ=
e SC");}
     auto sc =3D new SC();
     if (is(typeof(sc) =3D=3D C)) {writeln("type C");} else {writeln("ty=
pe SC");}
 }
=20 Java acts as D here: http://ideone.com/LcAll =20 http://ideone.com/AVFvI =20 =20 A D version that does as you desire: =20 import std.stdio; class SC { string f_ =3D "SC"; property string f() { return f_; } void show() { writeln(this.f); } } class C : SC { string f_ =3D "C"; property override string f() { return f_; } } void main () { auto c =3D new C(); writeln(c.classinfo.name); =20 auto sc =3D new SC(); writeln(sc.classinfo.name); =20 writeln(c.f); // "C" c.show(); // "C" } =20 Bye, bearophile
I just realised that what I was asking for is in fact class-level fields --= common to all instances, instead of each instance having it locally. Denis -- -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Nov 07 2010
parent Jesse Phillips <jessekphillips+D gmail.com> writes:
spir Wrote:

 I just realised that what I was asking for is in fact class-level fields --
common to all instances, instead of each instance having it locally.
 
Maybe you know the answer to that, but just in case you would use a static variable. class SC { static string f = "SC"; void show() {writeln(this.f);} }
Nov 07 2010