www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Please tell me this is a bug?

reply "Almighty Bob" <bob almighty.com> writes:
D version 2.066.1

int a = 42;
float b = 19;

a = b; // Error: cannot implicitly convert expression (b) of type 
float to int

a = a+b; // Error: cannot implicitly convert expression (b) of 
type float to int

but...

a += b; // Compiles with no ERROR!

Please tell me that's a bug?
Feb 21 2015
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Sunday, 22 February 2015 at 01:24:09 UTC, Almighty Bob wrote:
 Please tell me that's a bug?
Nope, a is clearly an int in the last case so no conversion is needed.
Feb 21 2015
parent reply "Almighty Bob" <bob almighty.com> writes:
On Sunday, 22 February 2015 at 01:32:16 UTC, Adam D. Ruppe wrote:
 On Sunday, 22 February 2015 at 01:24:09 UTC, Almighty Bob wrote:
 Please tell me that's a bug?
Nope, a is clearly an int in the last case so no conversion is needed.
a is an int in all three cases, b is a float in all three cases. In one case the compiler automatically converts b to an int before adding it to a. In the other two cases it gives an error. So.. a=a+b; a+=b; Are not the same, OK, it seems odd that a "shorthand" version of an expression would have slightly different semantics than the longhand version but fundamentally what bothers me is any automatic conversion from float to int. It should never be automatic. Ok I looked up the docs, and they say... http://dlang.org/expression.html "Assign Expressions: The right operand is implicitly converted to the type of the left operand" which quite clearly is not the case since... a=b; // causes an error. but.. a+=b; // does not.
Feb 21 2015
next sibling parent "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Sunday, 22 February 2015 at 02:15:29 UTC, Almighty Bob wrote:
 "Assign Expressions:
 The right operand is implicitly converted to the type of the 
 left operand"

 which quite clearly is not the case since...

 a=b; // causes an error. but..
 a+=b; // does not.
float does not *implicitly* convert to int. Required explicit coercion, which is what the opAssign expression does.
Feb 21 2015
prev sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Sunday, 22 February 2015 at 02:15:29 UTC, Almighty Bob wrote:
 what bothers me is any automatic conversion from float to int. 
 It should never be automatic.
Should 5.5 + 5 compile? I suppose it arguably shouldn't but that'd probably be pretty annoying and no information is lost - it can convert 5 (the int) to 5.0 (the float) and add it without dropping a part of the number. But int = float would truncate the decimal and that's not cool. You could argue this same logic ought to apply to a+=b and you'd have a point, but I think it is different because += happens in a single step: calculate in-place, rather than calculate the right hand side then assign to the left hand side. There's no intermediate to lose precision from, it is all done in that single step.
 "Assign Expressions:
 The right operand is implicitly converted to the type of the 
 left operand"

 which quite clearly is not the case since...

 a=b; // causes an error. but..
It tries to implicitly convert but can't.
Feb 21 2015
parent "Almighty Bob" <bob almighty.com> writes:
On Sunday, 22 February 2015 at 02:32:38 UTC, Adam D. Ruppe wrote:
 On Sunday, 22 February 2015 at 02:15:29 UTC, Almighty Bob wrote:
 what bothers me is any automatic conversion from float to int. 
 It should never be automatic.
Should 5.5 + 5 compile? I suppose it arguably shouldn't but that'd probably be pretty annoying and no information is lost - it can convert 5 (the int) to 5.0 (the float) and add it without dropping a part of the number.
Float arithmetic is already lossy, almost every float operation truncates and rounds, sticking an int in the mix does not change that. Int arithmetic is precise, putting a float in and automatically rounding it changes a precise equation to a lossy one. The point is if you have a float LHS then you are accepting lossy arithmetic as float is inherently lossy. If you have an int LHS you should be able to expect precise arithmetic. Most of what I do is DSP / data analysis. No only do I never want automatic float to int conversions, the majority of the time I actually want specific rounding when I do convert from float to int. IMO automatic float to int conversion is a terrible idea. It's worse than initialized floats because you can get results that look most OK, and it's a bugger to track down. And it's worse when the compiler has lulled you into a false sense of security by giving errors about not being able to convert floats to ints in most other cases.
Feb 22 2015
prev sibling parent reply "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Sunday, 22 February 2015 at 01:24:09 UTC, Almighty Bob wrote:
 a += b; // Compiles with no ERROR!

 Please tell me that's a bug?
Not a bug. From spec: http://dlang.org/expression.html#AssignExpression
 Assignment operator expressions, such as:
 
 a op= b
 
 are semantically equivalent to:
 
 a = cast(typeof(a))(a op b)
Seems questionable to me. Anyone know the rationale? If a = b; is disallowed, I don't see why a += b; should be more acceptable.
Feb 21 2015
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Sunday, 22 February 2015 at 02:27:30 UTC, Peter Alexander 
wrote:
 Seems questionable to me. Anyone know the rationale?
I actually agree it is a bit questionable, but I think the difference is += is, conceptually at least, atomic - it is a single function, append() instead of two calls, set(calculate()).
Feb 21 2015
next sibling parent "amber" <amber.swan gmail.com> writes:
On Sunday, 22 February 2015 at 02:35:02 UTC, Adam D. Ruppe wrote:
 On Sunday, 22 February 2015 at 02:27:30 UTC, Peter Alexander 
 wrote:
 Seems questionable to me. Anyone know the rationale?
I actually agree it is a bit questionable, but I think the difference is += is, conceptually at least, atomic - it is a single function, append() instead of two calls, set(calculate()).
Isn't that a compiler implementation detail though? I always considered a+=b as a shorthand for a=a+b so I find this surprising and a bit confusing. Maybe I need to revise my thinking on this :) /amber
Feb 21 2015
prev sibling parent reply "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Sunday, 22 February 2015 at 02:35:02 UTC, Adam D. Ruppe wrote:
 On Sunday, 22 February 2015 at 02:27:30 UTC, Peter Alexander 
 wrote:
 Seems questionable to me. Anyone know the rationale?
I actually agree it is a bit questionable, but I think the difference is += is, conceptually at least, atomic - it is a single function, append() instead of two calls, set(calculate()).
I can see where you are coming from, but the fact of the matter is that it is evaluated no differently than a = a + b. Why, in the a += b case, does it somehow become acceptable for the compiler to irresponsibly insert in an implicit narrowing conversion?
Feb 21 2015
parent "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 22 February 2015 at 02:52:47 UTC, Peter Alexander 
wrote:
 On Sunday, 22 February 2015 at 02:35:02 UTC, Adam D. Ruppe 
 wrote:
 On Sunday, 22 February 2015 at 02:27:30 UTC, Peter Alexander 
 wrote:
 Seems questionable to me. Anyone know the rationale?
I actually agree it is a bit questionable, but I think the difference is += is, conceptually at least, atomic - it is a single function, append() instead of two calls, set(calculate()).
I can see where you are coming from, but the fact of the matter is that it is evaluated no differently than a = a + b. Why, in the a += b case, does it somehow become acceptable for the compiler to irresponsibly insert in an implicit narrowing conversion?
It is only equivalent for integral greater than int. It is not for smaller integrals or floating point. See my other answer for rationale.
Feb 21 2015
prev sibling next sibling parent reply ketmar <ketmar ketmar.no-ip.org> writes:
On Sun, 22 Feb 2015 02:27:29 +0000, Peter Alexander wrote:

 On Sunday, 22 February 2015 at 01:24:09 UTC, Almighty Bob wrote:
 a +=3D b; // Compiles with no ERROR!

 Please tell me that's a bug?
=20 Not a bug. From spec: =20 http://dlang.org/expression.html#AssignExpression
 Assignment operator expressions, such as:
=20
 a op=3D b
=20
 are semantically equivalent to:
=20
 a =3D cast(typeof(a))(a op b)
=20 Seems questionable to me. Anyone know the rationale? If a =3D b; is disallowed, I don't see why a +=3D b; should be more acceptable.
it's fuuuuuunny! struct A { int v =3D 40; this (int n) { v =3D n; } int opOpAssign(string op) (A b) { return v+b.v; } } void main () { auto a =3D A(); a +=3D (cast(A)5); // import std.stdio; writeln(a.v); // can you guess the output? } 'cmon, guess it without executing the code! but don't ask me why this=20 psychodelic code can be compiled at all.=
Feb 21 2015
next sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
On Sun, 22 Feb 2015 03:15:25 +0000, ketmar wrote:

ooops. it compiles 'cause it's ok, and i'm outsmarted myself. nevermind.=
Feb 21 2015
prev sibling parent reply Daniel Kozak via Digitalmars-d <digitalmars-d puremagic.com> writes:
ketmar via Digitalmars-d píše v Ne 22. 02. 2015 v 03:15 +0000:
 On Sun, 22 Feb 2015 02:27:29 +0000, Peter Alexander wrote:
 
 On Sunday, 22 February 2015 at 01:24:09 UTC, Almighty Bob wrote:
 a += b; // Compiles with no ERROR!

 Please tell me that's a bug?
Not a bug. From spec: http://dlang.org/expression.html#AssignExpression
 Assignment operator expressions, such as:
 
 a op= b
 
 are semantically equivalent to:
 
 a = cast(typeof(a))(a op b)
Seems questionable to me. Anyone know the rationale? If a = b; is disallowed, I don't see why a += b; should be more acceptable.
it's fuuuuuunny! struct A { int v = 40; this (int n) { v = n; } int opOpAssign(string op) (A b) { return v+b.v; } } void main () { auto a = A(); a += (cast(A)5); // import std.stdio; writeln(a.v); // can you guess the output? } 'cmon, guess it without executing the code! but don't ask me why this psychodelic code can be compiled at all.
nothing has change because you dont assign anything to v so I guess you mean this code?: import std.stdio; struct A { int v = 40; this (int n) { v = n; } void opOpAssign(string op) (A b) { v+=b.v; } } void main () { auto a = A(); a += (cast(A)5); writeln(a.v); // can you guess the output? } than it would be obviosly 45
Feb 22 2015
parent ketmar <ketmar ketmar.no-ip.org> writes:
On Sun, 22 Feb 2015 21:08:34 +0100, Daniel Kozak via Digitalmars-d wrote:

 nothing has change because you dont assign anything to v so I guess you
 mean this code?:
i was trying to be smart, and failed. and i have a bad habit of noticing=20 my dumbyness right after i pressed ctrl+enter.=
Feb 22 2015
prev sibling next sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 22 February 2015 at 02:27:30 UTC, Peter Alexander 
wrote:
 On Sunday, 22 February 2015 at 01:24:09 UTC, Almighty Bob wrote:
 a += b; // Compiles with no ERROR!

 Please tell me that's a bug?
Not a bug. From spec: http://dlang.org/expression.html#AssignExpression
 Assignment operator expressions, such as:
 
 a op= b
 
 are semantically equivalent to:
 
 a = cast(typeof(a))(a op b)
Seems questionable to me. Anyone know the rationale? If a = b; is disallowed, I don't see why a += b; should be more acceptable.
The rationale make sens for things like : byte a; a += 1; Here, because of type promotion, a + 1 is an int, and if VRP of a is unknown, you can't cast implicitly back to byte. It is true that this create questionable side effect for float, but in the end, that is consistent, and it would be very annoying to not be able to increment/decrement integral smaller than int.
Feb 21 2015
next sibling parent "Daniel Murphy" <yebbliesnospam gmail.com> writes:
"deadalnix"  wrote in message news:wzpgqlnevhdmhsylumyq forum.dlang.org...

 The rationale make sens for things like :
 byte a; a += 1;

 Here, because of type promotion, a + 1 is an int, and if VRP of a is 
 unknown, you can't cast implicitly back to byte.

 It is true that this create questionable side effect for float, but in the 
 end, that is consistent, and it would be very annoying to not be able to 
 increment/decrement integral smaller than int.
We would still be able to accept that case if we required that the rhs implicitly converted to the rhs.
Feb 22 2015
prev sibling parent reply "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Sunday, 22 February 2015 at 07:11:24 UTC, deadalnix wrote:
 On Sunday, 22 February 2015 at 02:27:30 UTC, Peter Alexander 
 wrote:
 On Sunday, 22 February 2015 at 01:24:09 UTC, Almighty Bob 
 wrote:
 a += b; // Compiles with no ERROR!

 Please tell me that's a bug?
Not a bug. From spec: http://dlang.org/expression.html#AssignExpression
 Assignment operator expressions, such as:
 
 a op= b
 
 are semantically equivalent to:
 
 a = cast(typeof(a))(a op b)
Seems questionable to me. Anyone know the rationale? If a = b; is disallowed, I don't see why a += b; should be more acceptable.
The rationale make sens for things like : byte a; a += 1; Here, because of type promotion, a + 1 is an int, and if VRP of a is unknown, you can't cast implicitly back to byte.
If VRP is unknown then it should be disallowed for precisely that reason! It can't implicitly cast back to a byte, so it shouldn't. If you know that the int fits in a byte then do the cast yourself, that's what it's for.
 It is true that this create questionable side effect for float, 
 but in the end, that is consistent, and it would be very 
 annoying to not be able to increment/decrement integral smaller 
 than int.
Even if you forget about float, it's still inconsistent. byte a; int b; a = a + b; a += b; These do the same thing, and have the same pitfalls if the int is too big. Both should be disallowed.
Feb 22 2015
parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Sunday, 22 February 2015 at 14:18:24 UTC, Peter Alexander 
wrote:
 If VRP is unknown then it should be disallowed for precisely 
 that reason! It can't implicitly cast back to a byte, so it 
 shouldn't. If you know that the int fits in a byte then do the 
 cast yourself, that's what it's for.
Question though, how do you physically write the cast for: byte a; a += 1; With a + 1, you can cast that whole right hand side. But with +=1, there's nowhere to put the cast! If you cast(byte) 1, it changes nothing, since it could still overflow.
Feb 22 2015
prev sibling next sibling parent reply "ponce" <contact gam3sfrommars.fr> writes:
On Sunday, 22 February 2015 at 02:27:30 UTC, Peter Alexander 
wrote:
 On Sunday, 22 February 2015 at 01:24:09 UTC, Almighty Bob wrote:
 a += b; // Compiles with no ERROR!

 Please tell me that's a bug?
Not a bug. From spec: http://dlang.org/expression.html#AssignExpression
 Assignment operator expressions, such as:
 
 a op= b
 
 are semantically equivalent to:
 
 a = cast(typeof(a))(a op b)
Seems questionable to me. Anyone know the rationale? If a = b; is disallowed, I don't see why a += b; should be more acceptable.
Questionable or not, this is the C behaviour we might not depart from.
Feb 22 2015
next sibling parent "Almighty Bob" <bob almighty.com> writes:
On Sunday, 22 February 2015 at 09:59:36 UTC, ponce wrote:
 On Sunday, 22 February 2015 at 02:27:30 UTC, Peter Alexander 
 wrote:
 On Sunday, 22 February 2015 at 01:24:09 UTC, Almighty Bob 
 wrote:
 are semantically equivalent to:
 
 a = cast(typeof(a))(a op b)
Seems questionable to me. Anyone know the rationale? If a = b; is disallowed, I don't see why a += b; should be more acceptable.
Questionable or not, this is the C behaviour we might not depart from.
D has already departed from C, int a; float b; a = b; a = a+b; a += b; All 3 are valid in C, but only the later is valid in D. But at least with MSVC you can get warnings when you do such things.
Feb 22 2015
prev sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
On Sun, 22 Feb 2015 09:59:35 +0000, ponce wrote:

 On Sunday, 22 February 2015 at 02:27:30 UTC, Peter Alexander wrote:
 On Sunday, 22 February 2015 at 01:24:09 UTC, Almighty Bob wrote:
 a +=3D b; // Compiles with no ERROR!

 Please tell me that's a bug?
Not a bug. From spec: http://dlang.org/expression.html#AssignExpression
 Assignment operator expressions, such as:
=20
 a op=3D b
=20
 are semantically equivalent to:
=20
 a =3D cast(typeof(a))(a op b)
Seems questionable to me. Anyone know the rationale? If a =3D b; is disallowed, I don't see why a +=3D b; should be more acceptable.
=20 Questionable or not, this is the C behaviour we might not depart from.
but compiler can at least warn about implicit converting float to int.=20 one can always silence warning with `cast(int)f`. ER, anybody?=
Feb 22 2015
prev sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 2/21/15 9:27 PM, Peter Alexander wrote:
 On Sunday, 22 February 2015 at 01:24:09 UTC, Almighty Bob wrote:
 a += b; // Compiles with no ERROR!

 Please tell me that's a bug?
Not a bug. From spec: http://dlang.org/expression.html#AssignExpression
 Assignment operator expressions, such as:

 a op= b

 are semantically equivalent to:

 a = cast(typeof(a))(a op b)
Seems questionable to me. Anyone know the rationale? If a = b; is disallowed, I don't see why a += b; should be more acceptable.
I think the docs are misleading. For example, this doesn't work: int a; int *b = &a; a += b; Error: incompatible types for ((a) += (b)): 'int' and 'int*' But this does: a = cast(typeof(a))(a + b); I think it only works if it's a numeric narrowing conversion, but I don't know for sure. I would be happy if this behavior changed as the OP expected. But I'm glad there isn't exactly an unfettered implicit cast in every op= operation. Does anyone know the true rules for this, and can they please file an PR on the docs? -Steve
Feb 23 2015