digitalmars.D.learn - hijacking a class's members
- Rory Mcguire (56/56) Aug 04 2010 Hi,
- Mafi (10/24) Aug 04 2010 Hi,
- Rory Mcguire (31/64) Aug 04 2010 Thats what feels weird to me. a.x can result in different things happeni...
- Mafi (42/72) Aug 04 2010 If you want that to work, both x have to be virtual (ie dynamically
- Rory Mcguire (3/86) Aug 04 2010 cool thanks
- Stanislav Blinov (7/68) Aug 04 2010 Hi,
Hi, The code below is my beginning to attempt a class which implements any class and throws an exception if one tries to access any member of that class. Problem is that if I use: auto a1 = noinit!(A)(); it works and accesses the int x() {...} member of the generated class, but if I use: A a1 = noinit!(A)(); it accesses A.x instead of the generated classes x. So am I wrong in making a sub class have a member function which hides a parent class's member variable or is the compiler wrong and it should generate a call to generated sub class? Thanks!!! -Rory ================================================ import std.algorithm; import std.contracts; import std.traits; class A { int x; } string thrower(T)(string name) { static if (isNumeric!T) { return " property ref "~ T.stringof ~" "~ name ~"() { throw new Exception(\"Uninitialized access!\"); }" " property ref "~ T.stringof ~" "~ name ~"(int ignored) { throw new Exception(\"Uninitialized access\"); }"; } else { return "error"; } } string build(alias T, alias generator)(string myname) { string s = "auto "~ myname ~" = new class "~T.stringof~" { invariant() { throw new Exception(\"inv\");}\n"; foreach (i,t; typeof(T.tupleof)) { string name = find(T.tupleof[i].stringof, '.'); enforce(name.length >= 2); name = name[1..$]; //pragma(msg, t," ", A.tupleof[i]); s ~= "\t"~generator!t(name) ~"\n"; } return s~ "};"; } auto noinit(alias T)() { mixin(build!(T,thrower)("tmp")); return tmp; } void main() { A a = noinit!(A)(); auto a1 = noinit!(A)(); // pragma(msg, build!(A,thrower)("Athrower")); int i = a.x = 3; // uses A.x not the generated ??.x int j = a1.x = 3; // uses ??.x assert(a.x == 3); }
Aug 04 2010
Am 04.08.2010 12:11, schrieb Rory Mcguire:Hi, The code below is my beginning to attempt a class which implements any class and throws an exception if one tries to access any member of that class. Problem is that if I use: auto a1 = noinit!(A)(); it works and accesses the int x() {...} member of the generated class, but if I use: A a1 = noinit!(A)(); it accesses A.x instead of the generated classes x. So am I wrong in making a sub class have a member function which hides a parent class's member variable or is the compiler wrong and it should generate a call to generated sub class? Thanks!!! -RoryHi, if x is a field (ie a member variable) it's statically bound. In your example it is a field so it gets A.x of your subclass which is still there becuase of the methoda of A which could use A.x. Fields have to be statically bound because there's no covariance guarateed with them. Use getters and setters instead. BTW are propertys statically or dynamically bound. They're kind of both: fields and methods. Mafi
Aug 04 2010
Mafi wrote:Am 04.08.2010 12:11, schrieb Rory Mcguire:Thats what feels weird to me. a.x can result in different things happening even though x exists in both A and the generated class. However the generated class has two "fields" called x one you can't access anymore and the property one. When I create an instance of the generated class I would expect it to always to the same thing if I use one of its methods/properties/etc... Kind of like you would expect the following to print out "hello 2": class A { string toString() { return "hello"; } } class B : A { string toString() { return super.toString() ~ " 2"; } } void main() { A a = new B(); writeln(a.toString()); // uses B.toString() } What I've got is: class A { int x; } class B : A { int x() { throw new Exception(); } } void main() { A a = new B(); writeln(a.x); // this accesses A.x not B.x!!!! } just seems like properties are not quite right or something. -RoryHi, The code below is my beginning to attempt a class which implements any class and throws an exception if one tries to access any member of that class. Problem is that if I use: auto a1 = noinit!(A)(); it works and accesses the int x() {...} member of the generated class, but if I use: A a1 = noinit!(A)(); it accesses A.x instead of the generated classes x. So am I wrong in making a sub class have a member function which hides a parent class's member variable or is the compiler wrong and it should generate a call to generated sub class? Thanks!!! -RoryHi, if x is a field (ie a member variable) it's statically bound. In your example it is a field so it gets A.x of your subclass which is still there becuase of the methoda of A which could use A.x. Fields have to be statically bound because there's no covariance guarateed with them. Use getters and setters instead. BTW are propertys statically or dynamically bound. They're kind of both: fields and methods. Mafi
Aug 04 2010
Thats what feels weird to me. a.x can result in different things happening even though x exists in both A and the generated class. However the generated class has two "fields" called x one you can't access anymore and the property one. When I create an instance of the generated class I would expect it to always to the same thing if I use one of its methods/properties/etc... Kind of like you would expect the following to print out "hello 2": class A { string toString() { return "hello"; } } class B : A { string toString() { return super.toString() ~ " 2"; } } void main() { A a = new B(); writeln(a.toString()); // uses B.toString() } What I've got is: class A { int x; } class B : A { int x() { throw new Exception(); } } void main() { A a = new B(); writeln(a.x); // this accesses A.x not B.x!!!! } just seems like properties are not quite right or something. -RoryIf you want that to work, both x have to be virtual (ie dynamically bound). In D all non-final non-ststic clsss-methods are virtual(1). Consider the following: /////// class A { int x = 0; int getX() { //<-- it's virtual return x; } } class B : A{ int x = 5; override int getX() { //<-- it's virtual too return x; } } void thinAboutA(A a) { /* Now a call to a non virtual method * which results in vtbl lookup. a's vtbl * contains B.getX(). writeln(a.getX()); /* Non virtual field. * Has to be statically bound * to a lookup in A.x */ writeln(a.x); } void main() { thinkAboutA(new B); } //////// Fields have to be statically bound bcause the compiler doesn't enforce covariance with fields. So you can: /////////////// class C : A { string x = ""; } void main() { thinkAboutA(new C); //Should evrything crash now? I won't. } ////////////// 1) I'm not sure about propertys.
Aug 04 2010
Mafi wrote:cool thanks good exampleThats what feels weird to me. a.x can result in different things happening even though x exists in both A and the generated class. However the generated class has two "fields" called x one you can't access anymore and the property one. When I create an instance of the generated class I would expect it to always to the same thing if I use one of its methods/properties/etc... Kind of like you would expect the following to print out "hello 2": class A { string toString() { return "hello"; } } class B : A { string toString() { return super.toString() ~ " 2"; } } void main() { A a = new B(); writeln(a.toString()); // uses B.toString() } What I've got is: class A { int x; } class B : A { int x() { throw new Exception(); } } void main() { A a = new B(); writeln(a.x); // this accesses A.x not B.x!!!! } just seems like properties are not quite right or something. -RoryIf you want that to work, both x have to be virtual (ie dynamically bound). In D all non-final non-ststic clsss-methods are virtual(1). Consider the following: /////// class A { int x = 0; int getX() { //<-- it's virtual return x; } } class B : A{ int x = 5; override int getX() { //<-- it's virtual too return x; } } void thinAboutA(A a) { /* Now a call to a non virtual method * which results in vtbl lookup. a's vtbl * contains B.getX(). writeln(a.getX()); /* Non virtual field. * Has to be statically bound * to a lookup in A.x */ writeln(a.x); } void main() { thinkAboutA(new B); } //////// Fields have to be statically bound bcause the compiler doesn't enforce covariance with fields. So you can: /////////////// class C : A { string x = ""; } void main() { thinkAboutA(new C); //Should evrything crash now? I won't. } ////////////// 1) I'm not sure about propertys.
Aug 04 2010
04.08.2010 14:11, Rory Mcguire wrote:Hi, The code below is my beginning to attempt a class which implements any class and throws an exception if one tries to access any member of that class. Problem is that if I use: auto a1 = noinit!(A)(); it works and accesses the int x() {...} member of the generated class, but if I use: A a1 = noinit!(A)(); it accesses A.x instead of the generated classes x. So am I wrong in making a sub class have a member function which hides a parent class's member variable or is the compiler wrong and it should generate a call to generated sub class? Thanks!!! -Rory ================================================ import std.algorithm; import std.contracts; import std.traits; class A { int x; } string thrower(T)(string name) { static if (isNumeric!T) { return " property ref "~ T.stringof ~" "~ name ~"() { throw new Exception(\"Uninitialized access!\"); }" " property ref "~ T.stringof ~" "~ name ~"(int ignored) { throw new Exception(\"Uninitialized access\"); }"; } else { return "error"; } } string build(alias T, alias generator)(string myname) { string s = "auto "~ myname ~" = new class "~T.stringof~" { invariant() { throw new Exception(\"inv\");}\n"; foreach (i,t; typeof(T.tupleof)) { string name = find(T.tupleof[i].stringof, '.'); enforce(name.length>= 2); name = name[1..$]; //pragma(msg, t," ", A.tupleof[i]); s ~= "\t"~generator!t(name) ~"\n"; } return s~ "};"; } auto noinit(alias T)() { mixin(build!(T,thrower)("tmp")); return tmp; } void main() { A a = noinit!(A)(); auto a1 = noinit!(A)(); // pragma(msg, build!(A,thrower)("Athrower")); int i = a.x = 3; // uses A.x not the generated ??.x int j = a1.x = 3; // uses ??.x assert(a.x == 3); } =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Filtered-With-Copfilter: Version 0.84beta4 (ProxSMTP 1.8) Copfilter-Filtered-With: SpamAssassin 3.2.5 Copfilter-Virus-Scanned: ClamAV 0.94.2 by Markus Madlener http://www.copfilter.orgHi, You're working with 'a' through 'class A' public interface, because you plainly declared 'a' to be of 'class A'. A.x is not a function, but a member variable, so the compiler fairly accesses it as it should. Regards, Stanislav Blinov
Aug 04 2010