digitalmars.D - alias this doesn't work for properties.
- JS (24/24) Aug 01 2013 http://dpaste.dzfl.pl/0c923861
- John Colvin (4/28) Aug 01 2013 b.Y = 3 is rewritten as b.Y(3)
- JS (17/55) Aug 01 2013 This is wrong because
- John Colvin (40/45) Aug 01 2013 That's an interesting case. cast(A)b.Y) is using the B getter
- JS (39/87) Aug 01 2013 Ok, I don't know why you keep saying 3 cannot be "converted" to
- Adam D. Ruppe (29/30) Aug 01 2013 A working solution is to just use opAssign. I think of alias this
- Maxim Fomin (27/29) Aug 01 2013 http://dpaste.dzfl.pl/c3cce6e2
- John Colvin (9/39) Aug 02 2013 Ok... It doesn't work for structs though which is strange. The
- Jesse Phillips (21/21) Aug 01 2013 I'm going to provide a reduced case for the issue you are having.
- JS (25/47) Aug 01 2013 Um, but I'm not talking about a free function or member function
- Jesse Phillips (13/16) Aug 01 2013 Is it not headed anywhere? Are you not learning the design
- John Colvin (4/51) Aug 02 2013 In an ideal world, perhaps. There has been a huge amount of
- Tommi (4/16) Aug 02 2013 In the first case other modules can create a mutable pointer to
http://dpaste.dzfl.pl/0c923861 class A { double x; property double X() { return x; } property double X(double v) { return x = v; } alias X this; } class B { A a; property A Y() { return a; } property A Y(A v) { return a = v; } } void main() { B b = new B(); b.Y = 3; } error not a property of b.Y adding refs to the returns of the getters allows the code to work but only getters are called(hence the need for refs). Please allow alias this to work with overloaded functions. (specifically properties, b.Y = 3; is not b.Y() = 3 but b.Y(3);)
Aug 01 2013
On Thursday, 1 August 2013 at 20:42:08 UTC, JS wrote:http://dpaste.dzfl.pl/0c923861 class A { double x; property double X() { return x; } property double X(double v) { return x = v; } alias X this; } class B { A a; property A Y() { return a; } property A Y(A v) { return a = v; } } void main() { B b = new B(); b.Y = 3; } error not a property of b.Y adding refs to the returns of the getters allows the code to work but only getters are called(hence the need for refs). Please allow alias this to work with overloaded functions. (specifically properties, b.Y = 3; is not b.Y() = 3 but b.Y(3);)b.Y = 3 is rewritten as b.Y(3) You are asking for an "int" to be be implicitly convertable to an "A", which isn't possible.
Aug 01 2013
On Thursday, 1 August 2013 at 21:56:46 UTC, John Colvin wrote:On Thursday, 1 August 2013 at 20:42:08 UTC, JS wrote:This is wrong because (cast(A)b.Y) = 3; works. b.Y(3) should work because A is aliased to double. One of the issues is b.Y(3) The setter of B is never called. You are right that b.Y(3) does not accept an int(or double) BUT this is a bug in the compiler because it should since 3 can be assigned to it. It's just that the compiler isn't smart enough to see this because of the way it calculates the assignment. b.Y = 3 should do the same as b.a = 3 which should be the same as b.a.x = 3. If you think about what the code is actually doing you will see it should be possible. http://dpaste.dzfl.pl/ac376ca0http://dpaste.dzfl.pl/0c923861 class A { double x; property double X() { return x; } property double X(double v) { return x = v; } alias X this; } class B { A a; property A Y() { return a; } property A Y(A v) { return a = v; } } void main() { B b = new B(); b.Y = 3; } error not a property of b.Y adding refs to the returns of the getters allows the code to work but only getters are called(hence the need for refs). Please allow alias this to work with overloaded functions. (specifically properties, b.Y = 3; is not b.Y() = 3 but b.Y(3);)b.Y = 3 is rewritten as b.Y(3) You are asking for an "int" to be be implicitly convertible to an "A", which isn't possible.
Aug 01 2013
On Thursday, 1 August 2013 at 22:23:40 UTC, JS wrote:This is wrong because (cast(A)b.Y) = 3; works.That's an interesting case. cast(A)b.Y) is using the B getter property, which makes sense as, due to the cast, nothing in B can be called for the assigment. So you have (in psuedo-code, all properties expanded as getY/setY): b.getY.castToA = 3; wheras the previous example is: b.setY(3); Neither are an int being implicitly converted to an Ab.Y = 3 should do the same as b.a = 3 which should be the same as b.a.x = 3.Why that can't work: struct A { double x; alias x this; } struct B { private A a; property A Y() { importantGetPrep(); return a; } property void Y(A v) { importantSetPrep(); a = v; } } void main() { B b; b.Y = 3; //cannot be a call to the setter as cannot convert 3 to A . //cannot be a call to the getter followed by an assigment //as the assignment would then have no effect on b.a //due to value semantics. //cannot be anything else as it would bypass the //important*etPrep that must be called on all accesses //to B.a . } Putting functions like important*etPrep in properties are one of the main reasons why properties are useful, it would be a very bad idea to let them be circumvented by an implementation change in an internal struct.
Aug 01 2013
On Thursday, 1 August 2013 at 23:51:38 UTC, John Colvin wrote:On Thursday, 1 August 2013 at 22:23:40 UTC, JS wrote:Ok, I don't know why you keep saying 3 cannot be "converted" to A. Do you Realize that the ultimate goal is to assign 3 to x? 3 is an int and x is a double, there is no conversion issues here. if I do a = 3; b.Y = a; then it is no problem. The issue is that b.Y wants an A and ignores the alias, I think this is wrong behavior because when you alias A it is suppose to act like that type... in this case it doesn't. Simple as that. I can see why in some cases it is suppose to act the way it does, e.g., what if B.Y uses other fields of A, you obviously can't use a int then. If this is the case a run time error or compile time error should occur. In any case, I'll just overload the setter to accept double and be done with it. Arguing whether it is a flaw/limitation in D or a flaw/limitation in my thinking won't get the behavior I want. Note, I can just use a setter on double then it will work fine. This is not the behavior I want though because I breaks the homogeneity of my code generation. IMO, if the argument to a setter has an alias this, that type should also work for the argument. If the body of the setter uses things not in the aliased type then it it should be an error(in that case, you should overload the setter). This way you get the logical behavior expected but can also handle the more complex case. code: struct A { value double; int x; alias this value; } class B { property A prop(A v) { A a = new A; a.value = a.x; // error if v is double and no setter for double, remove line to make it work. return a; } // property A prop(double v) { ... } // specialize to prevent error for doubles This way for simple properties one gets the expected behavior for alias this.This is wrong because (cast(A)b.Y) = 3; works.That's an interesting case. cast(A)b.Y) is using the B getter property, which makes sense as, due to the cast, nothing in B can be called for the assigment. So you have (in psuedo-code, all properties expanded as getY/setY): b.getY.castToA = 3; wheras the previous example is: b.setY(3); Neither are an int being implicitly converted to an Ab.Y = 3 should do the same as b.a = 3 which should be the same as b.a.x = 3.Why that can't work: struct A { double x; alias x this; } struct B { private A a; property A Y() { importantGetPrep(); return a; } property void Y(A v) { importantSetPrep(); a = v; } } void main() { B b; b.Y = 3; //cannot be a call to the setter as cannot convert 3 to A . //cannot be a call to the getter followed by an assigment //as the assignment would then have no effect on b.a //due to value semantics. //cannot be anything else as it would bypass the //important*etPrep that must be called on all accesses //to B.a . } Putting functions like important*etPrep in properties are one of the main reasons why properties are useful, it would be a very bad idea to let them be circumvented by an implementation change in an internal struct.
Aug 01 2013
On Friday, 2 August 2013 at 00:36:19 UTC, JS wrote:Realize that the ultimate goal is to assign 3 to x?A working solution is to just use opAssign. I think of alias this as being implicit cast to , whereas opAssign is implicit cast from (well, sort of, it only works on assignments, but there's also constructors you can do. Where it falls short of full implicit cast is stuff like function calls) Anyway, try this: class A { double x; property double X() { return x; } property double X(double v) { return x = v; } alias X this; // new A opAssign(double rhs) { x = rhs; return this; } } Now: A a = new A(); a = 3.14; // ok Then the next question is b.Y = 3, which is one of those cases where it just isn't going to work like that. Y is pretty explicit about *wanting* an A, this isn't setting to an A, this would actually be implicit construction which is generally a no-no in D. However, if you add: property A Y(double v) { return a = v; } to class B, then it will compile, with a = v calling A.opAssign. A cool thing about opAssign that aias this doesn't do right now is it can be templated or you can overload it, and handle a vast variety of types.
Aug 01 2013
On Thursday, 1 August 2013 at 21:56:46 UTC, John Colvin wrote:You are asking for an "int" to be be implicitly convertable to an "A", which isn't possible.http://dpaste.dzfl.pl/c3cce6e2 import std.stdio; class A { double x; property double X() { writeln("From A.Get"); return x; } property double X(double v) { writeln("From A.Set"); x = v; return x; } alias X this; this(double val) { this.x = val; } } class B { A a; A Y() { writeln("From B.Get"); return a; } A Y(A v ...) { writeln("From B.Set"); a = v; return a; } this() { a = new A(0); } } void main() { B b = new B(); writeln(b.Y); b.Y = 3; writeln(b.Y); readln(); }
Aug 01 2013
On Friday, 2 August 2013 at 02:21:25 UTC, Maxim Fomin wrote:On Thursday, 1 August 2013 at 21:56:46 UTC, John Colvin wrote:Ok... It doesn't work for structs though which is strange. The docs do only mention classes however. That's not really an implicit conversion, it's an implicit contstruction. It's definitely not like alias this. (In your example the alias this is completely unused) Does this have any bearing on the wider question? The variadic class construction syntax could be allowed for properties, with a restriction to only one argument passed.You are asking for an "int" to be be implicitly convertable to an "A", which isn't possible.http://dpaste.dzfl.pl/c3cce6e2 import std.stdio; class A { double x; property double X() { writeln("From A.Get"); return x; } property double X(double v) { writeln("From A.Set"); x = v; return x; } alias X this; this(double val) { this.x = val; } } class B { A a; A Y() { writeln("From B.Get"); return a; } A Y(A v ...) { writeln("From B.Set"); a = v; return a; } this() { a = new A(0); } } void main() { B b = new B(); writeln(b.Y); b.Y = 3; writeln(b.Y); readln(); }
Aug 02 2013
I'm going to provide a reduced case for the issue you are having. struct Foo { double x; alias x this; } void main() { Foo a; a = 8; // Alias this assignment assert(a.x == 8); fun(7); // What you want } void fun(Foo a) { } You're claiming that since Foo is requested to "be" a double calling fun(7) should just assign 7 to x. What you're missing is that it is Foo which behaves like double, however fun(7) there is no Foo involved, it doesn't exist. You're actually requesting that a Foo is created, then to have an assignment of 7 to x of the new temporary Foo. This is not a bug, it is by design. Alias this is sugar of type it is declared in not the type it is declared to.
Aug 01 2013
On Friday, 2 August 2013 at 01:46:28 UTC, Jesse Phillips wrote:I'm going to provide a reduced case for the issue you are having. struct Foo { double x; alias x this; } void main() { Foo a; a = 8; // Alias this assignment assert(a.x == 8); fun(7); // What you want } void fun(Foo a) { } You're claiming that since Foo is requested to "be" a double calling fun(7) should just assign 7 to x. What you're missing is that it is Foo which behaves like double, however fun(7) there is no Foo involved, it doesn't exist. You're actually requesting that a Foo is created, then to have an assignment of 7 to x of the new temporary Foo. This is not a bug, it is by design. Alias this is sugar of type it is declared in not the type it is declared to.Um, but I'm not talking about a free function or member function but a property... they are suppose to be special else whats the point. They are suppose to wrap fields. Because of this "design" you speak of, I can't use a double wrapped(essentially) type because it is in an interface and I can't use a field in the interface. What is the difference between class A { int x; } class A { private int _x; property int x() { } property int x(int v) { } } ? From the outside world there is suppose to be no difference. The point of properties is to wrap a type... yet I can't do that.... and also because A is an interface there is not even a fallback to the using a field to get it to work. Anyways, this isn't headed anywhere... It's easy to sit back and try to analyze the situation without having ran into the problem directly.
Aug 01 2013
On Friday, 2 August 2013 at 01:55:35 UTC, JS wrote:Anyways, this isn't headed anywhere... It's easy to sit back and try to analyze the situation without having ran into the problem directly.Is it not headed anywhere? Are you not learning the design choices of D and why those choices where chosen over others? Are you not learning the limitations that will be placed on you so that in the future you can select a design which matches those limitations? D has many flaws and it is missing polish in many places. You've been putting CTFE and other features through their pases, yet instead of feeling that your are learning something you feel that it "isn't headed anywhere?" There is much bickering about what properties are, but one thing we know is they can not act exactly like fields. So you're expectations are off here, and I too am disappointed.
Aug 01 2013
On Friday, 2 August 2013 at 01:55:35 UTC, JS wrote:On Friday, 2 August 2013 at 01:46:28 UTC, Jesse Phillips wrote:In an ideal world, perhaps. There has been a huge amount of discussion about properties here before and no solution is perfect.I'm going to provide a reduced case for the issue you are having. struct Foo { double x; alias x this; } void main() { Foo a; a = 8; // Alias this assignment assert(a.x == 8); fun(7); // What you want } void fun(Foo a) { } You're claiming that since Foo is requested to "be" a double calling fun(7) should just assign 7 to x. What you're missing is that it is Foo which behaves like double, however fun(7) there is no Foo involved, it doesn't exist. You're actually requesting that a Foo is created, then to have an assignment of 7 to x of the new temporary Foo. This is not a bug, it is by design. Alias this is sugar of type it is declared in not the type it is declared to.Um, but I'm not talking about a free function or member function but a property... they are suppose to be special else whats the point. They are suppose to wrap fields. Because of this "design" you speak of, I can't use a double wrapped(essentially) type because it is in an interface and I can't use a field in the interface. What is the difference between class A { int x; } class A { private int _x; property int x() { } property int x(int v) { } } ? From the outside world there is suppose to be no difference.
Aug 02 2013
On Friday, 2 August 2013 at 01:55:35 UTC, JS wrote:What is the difference between class A { int x; } class A { private int _x; property int x() { } property int x(int v) { } } ? From the outside world there is suppose to be no difference.In the first case other modules can create a mutable pointer to the field x. In the second case other modules cannot create any pointer to field _x.
Aug 02 2013