digitalmars.D - opAssign() still accepted for classes???
- Alexander (20/20) Apr 29 2011 Doing some experiments, and after conversion of struct into a class I've...
- Steven Schveighoffer (8/12) Apr 29 2011 opAssign is only invalid if you are assigning something that implicitly ...
- Alexander (6/8) Apr 29 2011 Well, the documentation says: "The assignment operator = can be overlo...
- Steven Schveighoffer (12/24) Apr 29 2011 That's puzzling. The D1 docs say "struct or class aggregate". So it was...
- Alexander (9/11) Apr 29 2011 Well, the fact is - it maps. If I've static opAssign() defined, it is ...
- Steven Schveighoffer (14/30) Apr 29 2011 That most certainly is a bug.
- Alexander (3/4) Apr 29 2011 Second thought... Since compiler *knows* that the pointer is null at t...
- KennyTM~ (10/14) Apr 29 2011 That requires data flow analysis. For example, how could the compiler
- Steven Schveighoffer (5/24) Apr 29 2011 I think he was referring to the line:
- KennyTM~ (2/6) Apr 29 2011 That's definitely a bug. Why should a declaration call opAssign?
- Steven Schveighoffer (17/26) Apr 29 2011 X x = new X;
- Steven Schveighoffer (5/8) Apr 29 2011 Meant to say, I wouldn't mind if it was an error. I don't think it's a ...
- KennyTM~ (18/45) Apr 29 2011 I see.
- Steven Schveighoffer (4/20) Apr 29 2011 Interesting! So this is definitely an inconsistency that indicates the ...
- Alexander (6/11) Apr 29 2011 Exactly. And, BTW, code
Doing some experiments, and after conversion of struct into a class I've found that opAssign(), contrary to what documentation says, is silently accepted for classes (in D 2.052) What is worse, it segfaults when object is not constructed first: ---snip--- class X { int v; typeof(this) opAssign(int i) { v = i; return this; } } void main() { X x0 = new X(); x0 = 0; // ok X x1 = 0; // segfault } ---snip-- Well, I understand why it segfaults, but shouldn't opAssign() be disallowed? If documentation is wrong, and it is still valid for classes, this should be handled somehow else. /Alexander
Apr 29 2011
On Fri, 29 Apr 2011 10:43:56 -0400, Alexander <aldem+dmars nk7.net> wrote:Doing some experiments, and after conversion of struct into a class I've found that opAssign(), contrary to what documentation says, is silently accepted for classes (in D 2.052)opAssign is only invalid if you are assigning something that implicitly converts to that type. So this will fail: typeof(this) opAssign(typeof(this) otherthing) {...}What is worse, it segfaults when object is not constructed first:x = y is equivalent to x.opAssign(y). So x is null, you are dereferencing a null pointer. -Steve
Apr 29 2011
On 29.04.2011 17:05, Steven Schveighoffer wrote:opAssign is only invalid if you are assigning something that implicitly converts to that type.Well, the documentation says: "The assignment operator = can be overloaded if the lvalue is a struct aggregate, and opAssign is a member function of that aggregate." Thus, I assume that for classes it shouldn't be possible, or did I get it wrong?x = y is equivalent to x.opAssign(y). So x is null, you are dereferencing a null pointer.This I understand, of course - the main point is why it is accepted for objects at all. BTW, it seems that overloads can be static - what is the semantic of static overload? (static opAssign() also fails). /Alexander
Apr 29 2011
On Fri, 29 Apr 2011 11:20:16 -0400, Alexander <aldem+dmars nk7.net> wrote:On 29.04.2011 17:05, Steven Schveighoffer wrote:That's puzzling. The D1 docs say "struct or class aggregate". So it was obviously removed in some version of the docs, but I'm not sure why. Walter?opAssign is only invalid if you are assigning something that implicitly converts to that type.Well, the documentation says: "The assignment operator = can be overloaded if the lvalue is a struct aggregate, and opAssign is a member function of that aggregate."OK, some don't initially grasp that classes need to be initialized, I thought you were asking why the segfault occurs.x = y is equivalent to x.opAssign(y). So x is null, you are dereferencing a null pointer.This I understand, of course - the main point is why it is accepted for objects at all.BTW, it seems that overloads can be static - what is the semantic of static overload? (static opAssign() also fails).Static opCall is possible, but I wasn't aware of the other operator overloads being possible. Note that opAssign is a valid symbol name, so it can be used in places even where it doesn't overload assignment, such as a static or global function. It just won't map to any operator usage. -Steve
Apr 29 2011
On 29.04.2011 18:13, Steven Schveighoffer wrote:Static opCall is possible, but I wasn't aware of the other operator overloads being possible.I wasn't too - it is not mentioned anywhere, just tried it.Note that opAssign is a valid symbol name, so it can be used in places even where it doesn't overload assignment, such as a static or global function. It just won't map to any operator usage.Well, the fact is - it maps. If I've static opAssign() defined, it is called when I assign something to an object. Even more fun - static opAdd() maps too, and - wow! - if it returns new object, i.e. construction like: X x; x = x + 3; then it will allocate new instance of X, where: static typeof(this) opAdd(int i) { return new X(i); } I am impressed... :) /Alexander
Apr 29 2011
On Fri, 29 Apr 2011 12:25:40 -0400, Alexander <aldem+dmars nk7.net> wrote:On 29.04.2011 18:13, Steven Schveighoffer wrote:That most certainly is a bug. What I think is happening is you can call static functions with an instance of that type, but the instance isn't passed to it, it's just used as a namespace. This is a "feature" that I continue to feel is a bug. So for example, you might expect: x = new X(4); x = x + 3; assert(x.value == 7) but it will fail, because: x.opAdd(3) doesn't actually pass x into the function! So there is no way you could possibly know what the left hand side of the operator is! -SteveStatic opCall is possible, but I wasn't aware of the other operator overloads being possible.I wasn't too - it is not mentioned anywhere, just tried it.Note that opAssign is a valid symbol name, so it can be used in places even where it doesn't overload assignment, such as a static or global function. It just won't map to any operator usage.Well, the fact is - it maps. If I've static opAssign() defined, it is called when I assign something to an object. Even more fun - static opAdd() maps too, and - wow! - if it returns new object, i.e. construction like: X x; x = x + 3; then it will allocate new instance of X, where: static typeof(this) opAdd(int i) { return new X(i); } I am impressed... :)
Apr 29 2011
On 29.04.2011 17:05, Steven Schveighoffer wrote:x = y is equivalent to x.opAssign(y). So x is null, you are dereferencing a null pointer.Second thought... Since compiler *knows* that the pointer is null at this point, shouldn't it produce a warning at least? /Alexander
Apr 29 2011
On Apr 30, 11 00:14, Alexander wrote:On 29.04.2011 17:05, Steven Schveighoffer wrote:That requires data flow analysis. For example, how could the compiler knows the 'x' below is 'null'? K x; if (veryComplexCondition(y)) x = new K; x = 4.0; // <---- See http://www.digitalmars.com/d/2.0/faq.html#nan. (That said, I see no problem treating this as a warning (which is outside of the D spec) if a variable is provable 'null'.)x = y is equivalent to x.opAssign(y). So x is null, you are dereferencing a null pointer.Second thought... Since compiler *knows* that the pointer is null at this point, shouldn't it produce a warning at least? /Alexander
Apr 29 2011
On Fri, 29 Apr 2011 13:03:05 -0400, KennyTM~ <kennytm gmail.com> wrote:On Apr 30, 11 00:14, Alexander wrote:I think he was referring to the line: X x = 0; Where x could not possibly be anything other than null. -SteveOn 29.04.2011 17:05, Steven Schveighoffer wrote:That requires data flow analysis. For example, how could the compiler knows the 'x' below is 'null'? K x; if (veryComplexCondition(y)) x = new K; x = 4.0; // <---- See http://www.digitalmars.com/d/2.0/faq.html#nan. (That said, I see no problem treating this as a warning (which is outside of the D spec) if a variable is provable 'null'.)x = y is equivalent to x.opAssign(y). So x is null, you are dereferencing a null pointer.Second thought... Since compiler *knows* that the pointer is null at this point, shouldn't it produce a warning at least? /Alexander
Apr 29 2011
On Apr 30, 11 01:19, Steven Schveighoffer wrote:I think he was referring to the line: X x = 0; Where x could not possibly be anything other than null. -SteveThat's definitely a bug. Why should a declaration call opAssign?
Apr 29 2011
On Fri, 29 Apr 2011 13:29:56 -0400, KennyTM~ <kennytm gmail.com> wrote:On Apr 30, 11 01:19, Steven Schveighoffer wrote:X x = new X; is equivalent to X x; x = new X; new X is an expression, which doesn't have to be the rvalue of an assignment, I suppose you can substitute any valid expression for it: X x; x = 0; => X x = 0; Also, if X is a struct, and the struct defines opAssign(int), this would be valid. I wouldn't mind if it was a bug, because clearly you never want to call opAssign on an uninitialized class. But it definitely would be a special case. -SteveI think he was referring to the line: X x = 0; Where x could not possibly be anything other than null. -SteveThat's definitely a bug. Why should a declaration call opAssign?
Apr 29 2011
On Fri, 29 Apr 2011 13:36:20 -0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:I wouldn't mind if it was a bug, because clearly you never want to call opAssign on an uninitialized class. But it definitely would be a special case.Meant to say, I wouldn't mind if it was an error. I don't think it's a bug exactly... -Steve
Apr 29 2011
On Apr 30, 11 01:36, Steven Schveighoffer wrote:On Fri, 29 Apr 2011 13:29:56 -0400, KennyTM~ <kennytm gmail.com> wrote:I see. Though this isn't valid with a 'struct'. ------------------------ import std.stdio; struct K { K opAssign(int x) { writeln(x); return this; } } void main() { // K k = 8; // Error: cannot implicitly convert expression (8) of type int to K K k; k = 8; // OK. } ------------------------On Apr 30, 11 01:19, Steven Schveighoffer wrote:X x = new X; is equivalent to X x; x = new X; new X is an expression, which doesn't have to be the rvalue of an assignment, I suppose you can substitute any valid expression for it: X x; x = 0; => X x = 0; Also, if X is a struct, and the struct defines opAssign(int), this would be valid. I wouldn't mind if it was a bug, because clearly you never want to call opAssign on an uninitialized class. But it definitely would be a special case. -SteveI think he was referring to the line: X x = 0; Where x could not possibly be anything other than null. -SteveThat's definitely a bug. Why should a declaration call opAssign?
Apr 29 2011
On Fri, 29 Apr 2011 13:49:19 -0400, KennyTM~ <kennytm gmail.com> wrote:Though this isn't valid with a 'struct'. ------------------------ import std.stdio; struct K { K opAssign(int x) { writeln(x); return this; } } void main() { // K k = 8; // Error: cannot implicitly convert expression (8) of type int to K K k; k = 8; // OK. } ------------------------Interesting! So this is definitely an inconsistency that indicates the class version is a bug. -Steve
Apr 29 2011
On Apr 30, 11 01:54, Steven Schveighoffer wrote:On Fri, 29 Apr 2011 13:49:19 -0400, KennyTM~ <kennytm gmail.com> wrote:That said, for a 'struct' the 'Type var = expr;' declaration is expected to call the constructor: --------------------- import std.stdio; struct K { this(int x) { writeln(x); } } void main() { K k = 8; } ---------------------Though this isn't valid with a 'struct'. ------------------------ import std.stdio; struct K { K opAssign(int x) { writeln(x); return this; } } void main() { // K k = 8; // Error: cannot implicitly convert expression (8) of type int to K K k; k = 8; // OK. } ------------------------Interesting! So this is definitely an inconsistency that indicates the class version is a bug. -Steve
Apr 29 2011
On Apr 30, 11 01:54, Steven Schveighoffer wrote:On Fri, 29 Apr 2011 13:49:19 -0400, KennyTM~ <kennytm gmail.com> wrote:Turns out it is an old bug. http://d.puremagic.com/issues/show_bug.cgi?id=671Though this isn't valid with a 'struct'. ------------------------ import std.stdio; struct K { K opAssign(int x) { writeln(x); return this; } } void main() { // K k = 8; // Error: cannot implicitly convert expression (8) of type int to K K k; k = 8; // OK. } ------------------------Interesting! So this is definitely an inconsistency that indicates the class version is a bug. -Steve
Apr 29 2011
On 29.04.2011 19:19, Steven Schveighoffer wrote:I think he was referring to the line: X x = 0; Where x could not possibly be anything other than null.Exactly. And, BTW, code X x; x = 0; is correctly detected as a null dereference at compile time. /Alexander
Apr 29 2011