digitalmars.D.learn - auto limitation?
- Namespace (8/8) Sep 11 2012 I have this code, but it works not as expected:
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (25/32) Sep 11 2012 Here is a reduced code:
- Namespace (5/29) Sep 11 2012 I should begin to count the bugs I find with stuff like this. :)
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (23/57) Sep 11 2012 Please create a bug about this one:
- Namespace (2/2) Sep 11 2012 That's not what i want. I would avoid casting if it's possible.
- Simen Kjaeraas (5/8) Sep 11 2012 std.traits.CommonType.
- Denis Shelomovskij (11/12) Sep 11 2012 typeof(return)
- Maxim Fomin (17/25) Sep 11 2012 I guess it may be reduced to:
- Namespace (1/5) Sep 11 2012 But i thought Variant is one. ;)
- Maxim Fomin (8/13) Sep 11 2012 I guess (never used Variant) that it uses templated getter which
- Simen Kjaeraas (8/11) Sep 11 2012 I'd be surprised if this were not a bug. My expectation would be that th...
- Maxim Fomin (6/18) Sep 11 2012 It can do, but in compile time. At runtime it cannot know what
- Namespace (6/6) Sep 11 2012 With multiple alias this this should work.
- Timon Gehr (4/8) Sep 11 2012 Exactly. If it was UB, the spec would say the behaviour is undefined if
- Namespace (2/11) Sep 11 2012 So what? Should my code work or not?
- Timon Gehr (2/18) Sep 11 2012 According to the spec it should fail compilation.
- Namespace (1/1) Sep 11 2012 Ah ok. That's sad.
- Namespace (3/3) Sep 11 2012 My final implementation:
- Maxim Fomin (4/5) Sep 11 2012 After rethinking it I agree that bug is in faulty compilation
- bearophile (21/23) Sep 11 2012 I suggest to file a bug:
- Namespace (3/26) Sep 11 2012 Sure that is the first i will do tomorrow.
- Jonathan M Davis (12/14) Sep 11 2012 Use a cast. auto _cannot_ be different types depending on what you retur...
- bearophile (18/19) Sep 11 2012 This seems to work, but solutions that use cast() are sometimes
- Jonathan M Davis (5/25) Sep 11 2012 If you're going to use a cast, then use one where you give the type
- Jonathan M Davis (11/14) Sep 11 2012 And actually, in all honesty, I see no reason to use auto here. If you k...
- Namespace (12/12) Sep 11 2012 You mean so?
- Jonathan M Davis (14/28) Sep 11 2012 If want the result to always be the same type, then either use the expli...
- Graham Fawcett (17/50) Sep 11 2012 Just this one. You can use an anonymous union in your Num struct,
- Namespace (1/1) Sep 12 2012 Done, thank you. :)
I have this code, but it works not as expected: http://dpaste.dzfl.pl/6ce5b4dd I get 0 instead of 42 if my type is Int. My value is correct (as you can see) but "writeln" prints still 0 instead of 42. I think "auto" compiles first to float and cannot handle then integers. Am I right? And could you explain me how this could work?
Sep 11 2012
On 09/11/2012 11:10 AM, Namespace wrote:I have this code, but it works not as expected: http://dpaste.dzfl.pl/6ce5b4dd I get 0 instead of 42 if my type is Int. My value is correct (as you can see) but "writeln" prints still 0 instead of 42. I think "auto" compiles first to float and cannot handle then integers. Am I right? And could you explain me how this could work?Here is a reduced code: import std.stdio; enum Type { Int, Float } auto foo(Type t) { final switch (t) { case Type.Int: return 42; case Type.Float: return 1.5; } } void main() { writeln(foo(Type.Int)); writeln(foo(Type.Float)); } The return type of foo() is double. (It's float in your code but it doesn't matter.) I think this is a bug. I guess that 'return 42' is still placing an int onto the program stack instead of a float. A workarounds are returning to!float(this._num.ivalue). But I think this is a compiler bug. Ali
Sep 11 2012
Here is a reduced code: import std.stdio; enum Type { Int, Float } auto foo(Type t) { final switch (t) { case Type.Int: return 42; case Type.Float: return 1.5; } } void main() { writeln(foo(Type.Int)); writeln(foo(Type.Float)); } The return type of foo() is double. (It's float in your code but it doesn't matter.) I think this is a bug. I guess that 'return 42' is still placing an int onto the program stack instead of a float. A workarounds are returning to!float(this._num.ivalue). But I think this is a compiler bug. AliI should begin to count the bugs I find with stuff like this. :) So no correct workaround, hm? I tried to use a Variant and in the getter method "get" and even "coerce" but then i get the error, that the type of "get" cannot be detected.
Sep 11 2012
On 09/11/2012 11:40 AM, Namespace wrote:Please create a bug about this one: http://d.puremagic.com/issues/ But wait until someone else confirms that it really is a bug. :)Here is a reduced code: import std.stdio; enum Type { Int, Float } auto foo(Type t) { final switch (t) { case Type.Int: return 42; case Type.Float: return 1.5; } } void main() { writeln(foo(Type.Int)); writeln(foo(Type.Float)); } The return type of foo() is double. (It's float in your code but it doesn't matter.) I think this is a bug. I guess that 'return 42' is still placing an int onto the program stack instead of a float. A workarounds are returning to!float(this._num.ivalue). But I think this is a compiler bug. AliI should begin to count the bugs I find with stuff like this. :)So no correct workaround, hm?You have to cast the types to the largest one. The following does not work because foo() is not defined yet: import std.traits; // ... auto foo(Type t) { final switch (t) { case Type.Int: return to!(ReturnType!(typeof(&foo)))(42); case Type.Float: return 1.5; } } Error: forward reference to foo Explicitly casting is a way: return to!double(42); Or you can write or find a template that produces the largest type among the members of a union. Ali
Sep 11 2012
That's not what i want. I would avoid casting if it's possible. I hope it is a bug and will fixed in 2.061.
Sep 11 2012
On Tue, 11 Sep 2012 20:48:25 +0200, Ali =C3=87ehreli <acehreli yahoo.com=wrote:Or you can write or find a template that produces the largest type amo=ng =the members of a union.std.traits.CommonType. -- = Simen
Sep 11 2012
11.09.2012 22:48, Ali Çehreli пишет:return to!(ReturnType!(typeof(&foo)))(42);typeof(return) See http://dlang.org/declaration.html#typeof Anyway don't use it as a type of the first return. You will get: --- Error: cannot use typeof(return) inside function foo with inferred return type --- -- Денис В. Шеломовский Denis V. Shelomovskij
Sep 11 2012
On Tuesday, 11 September 2012 at 18:32:47 UTC, Ali Çehreli wrote:Here is a reduced code:I guess it may be reduced to: auto foo(bool val) { if (val) return 42; else return 1.5; } void main() { assert(foo(true) == 42); // assertion failure assert(foo(false) == 1.5); }The return type of foo() is double. (It's float in your code but it doesn't matter.) I think this is a bug. I guess that 'return 42' is still placing an int onto the program stack instead of a float. A workarounds are returning to!float(this._num.ivalue). But I think this is a compiler bug. AliI think it is UB rather than a bug. The spec says that return types must match exactly. AFAIK auto is a feature to infer return type, not to magically adjust to multiple incompatible types.
Sep 11 2012
I think it is UB rather than a bug. The spec says that return types must match exactly. AFAIK auto is a feature to infer return type, not to magically adjust to multiple incompatible types.But i thought Variant is one. ;)
Sep 11 2012
On Tuesday, 11 September 2012 at 19:03:56 UTC, Namespace wrote:I guess (never used Variant) that it uses templated getter which correctly returns value. Float values are returned in %xmm registers and integer values are returned in %eax. Without knowing return type a caller doesn't know where to take return value. For example in this case foo function correctly places return values, but main takes in both cases return value from %xmm.I think it is UB rather than a bug. The spec says that return types must match exactly. AFAIK auto is a feature to infer return type, not to magically adjust to multiple incompatible types.But i thought Variant is one. ;)
Sep 11 2012
On Tue, 11 Sep 2012 20:57:07 +0200, Maxim Fomin <maxim maxim-fomin.ru> wrote:I think it is UB rather than a bug. The spec says that return types must match exactly. AFAIK auto is a feature to infer return type, not to magically adjust to multiple incompatible types.I'd be surprised if this were not a bug. My expectation would be that the types be combined as with the ?: operator, just like std.traits.CommonType. If this is not a bug, it's certainly worth filing as an enhancement request. -- Simen
Sep 11 2012
On Tuesday, 11 September 2012 at 19:07:52 UTC, Simen Kjaeraas wrote:On Tue, 11 Sep 2012 20:57:07 +0200, Maxim Fomin <maxim maxim-fomin.ru> wrote:It can do, but in compile time. At runtime it cannot know what type is returned (I suppose, but I am not expert in such things). Variant works because it does it in compile time, but buggy examples published so far do it at runtime.I think it is UB rather than a bug. The spec says that return types must match exactly. AFAIK auto is a feature to infer return type, not to magically adjust to multiple incompatible types.I'd be surprised if this were not a bug. My expectation would be that the types be combined as with the ?: operator, just like std.traits.CommonType. If this is not a bug, it's certainly worth filing as an enhancement request.
Sep 11 2012
With multiple alias this this should work. int getInt() const { return this.ivalue; } alias getInt this; float getFloat() const { return this.fvalue; } alias getFloat this; Or with a class method for implicit conversion.
Sep 11 2012
On 09/11/2012 08:57 PM, Maxim Fomin wrote:I think it is UB rather than a bug.No, this is a bug.The spec says that return types must match exactly.Exactly. If it was UB, the spec would say the behaviour is undefined if they don't match exactly.AFAIK auto is a feature to infer return type, not to magically adjust to multiple incompatible types.
Sep 11 2012
On Tuesday, 11 September 2012 at 19:27:40 UTC, Timon Gehr wrote:On 09/11/2012 08:57 PM, Maxim Fomin wrote:So what? Should my code work or not?I think it is UB rather than a bug.No, this is a bug.The spec says that return types must match exactly.Exactly. If it was UB, the spec would say the behaviour is undefined if they don't match exactly.AFAIK auto is a feature to infer return type, not to magically adjust to multiple incompatible types.
Sep 11 2012
On 09/11/2012 09:29 PM, Namespace wrote:On Tuesday, 11 September 2012 at 19:27:40 UTC, Timon Gehr wrote:According to the spec it should fail compilation.On 09/11/2012 08:57 PM, Maxim Fomin wrote:So what? Should my code work or not?I think it is UB rather than a bug.No, this is a bug.The spec says that return types must match exactly.Exactly. If it was UB, the spec would say the behaviour is undefined if they don't match exactly.AFAIK auto is a feature to infer return type, not to magically adjust to multiple incompatible types.
Sep 11 2012
My final implementation: http://dpaste.dzfl.pl/4d2a045a Any suggestions?
Sep 11 2012
On Tuesday, 11 September 2012 at 19:35:58 UTC, Timon Gehr wrote:According to the spec it should fail compilation.After rethinking it I agree that bug is in faulty compilation (assuming spec is correct), not in returning zero at runtime, which was thought previously.
Sep 11 2012
Namespace:I have this code, but it works not as expected: http://dpaste.dzfl.pl/6ce5b4ddI suggest to file a bug: auto foo(bool b) { final switch (b) { case true: return 10; case false: return 20.0; } } void main() { import std.stdio: writeln; writeln(foo(true)); writeln(foo(false)); } The acceptable results are a compile-time error for type mismatch, or a conversion of both literals to double. Probably the second is better. But a silent bit-level cast is not acceptable. Bye, bearophile
Sep 11 2012
On Tuesday, 11 September 2012 at 21:13:02 UTC, bearophile wrote:Namespace:Sure that is the first i will do tomorrow. But so far no suggestions?I have this code, but it works not as expected: http://dpaste.dzfl.pl/6ce5b4ddI suggest to file a bug: auto foo(bool b) { final switch (b) { case true: return 10; case false: return 20.0; } } void main() { import std.stdio: writeln; writeln(foo(true)); writeln(foo(false)); } The acceptable results are a compile-time error for type mismatch, or a conversion of both literals to double. Probably the second is better. But a silent bit-level cast is not acceptable. Bye, bearophile
Sep 11 2012
On Tuesday, September 11, 2012 23:31:43 Namespace wrote:Sure that is the first i will do tomorrow. But so far no suggestions?Use a cast. auto _cannot_ be different types depending on what you return. It must always resolve to the same type. So, in this case, either it needs to resolve to double (in which case the compiler should case) or fail to compile. If you really want the type of the return type to be different depending on what you return, you need to use Variant (in which case it _still_ won't really be different, it'll just always be Variant, but Variant will hold a different value in its internal union, and you'll be able to get that value out as its original type later, because the Variant knows what it was). But D is statically typed, so all types must be known at compile time, and you can't have types changing based on the path of execution. - Jonathan M Davis
Sep 11 2012
Namespace:But so far no suggestions?This seems to work, but solutions that use cast() are sometimes fragile (and dangerous): auto foo(bool b) { final switch (b) { case false: return 20.0; case true: return cast(typeof(return))10; } } void main() { import std.stdio: writeln; writeln(foo(false)); writeln(foo(true)); } Bye, bearophile
Sep 11 2012
On Tuesday, September 11, 2012 23:55:40 bearophile wrote:Namespace:If you're going to use a cast, then use one where you give the type explicitly. Using typeof(return) is just asking for it when the compiler is clearly already having issues with the return type. - Jonathan M DavisBut so far no suggestions?This seems to work, but solutions that use cast() are sometimes fragile (and dangerous): auto foo(bool b) { final switch (b) { case false: return 20.0; case true: return cast(typeof(return))10; } } void main() { import std.stdio: writeln; writeln(foo(false)); writeln(foo(true)); }
Sep 11 2012
On Tuesday, September 11, 2012 15:14:43 Jonathan M Davis wrote:If you're going to use a cast, then use one where you give the type explicitly. Using typeof(return) is just asking for it when the compiler is clearly already having issues with the return type.And actually, in all honesty, I see no reason to use auto here. If you know what the return type is supposed to be (e.g. double), then just use double. Casting where it's unnecessary is just begging for bugs. Based on Namespace's posts in this thread, I get the impression that what he wanted was that the return type would be either int or double depending on the value returned - i.e. he was trying to get dynamic typing - which doesn't work, because D is a static language. If that's what he wants, he needs to use Variant, and casting and the like is going to do him no good. auto was the wrong choice in the first place. - Jonathan M Davis
Sep 11 2012
You mean so? ref Variant get() { return this._num; // with Variant _num; } alias get this; and then: int i = zahl.get!int? No. Then I use my solution as you can see on DPaste. If Variant works only this way I can also set float to the return type an cast if I need to int. And with my solution I have in calculation a numeric value and doesn't have to cast with Variant's get method.
Sep 11 2012
On Wednesday, September 12, 2012 00:29:32 Namespace wrote:You mean so? ref Variant get() { return this._num; // with Variant _num; } alias get this; and then: int i = zahl.get!int? No. Then I use my solution as you can see on DPaste. If Variant works only this way I can also set float to the return type an cast if I need to int. And with my solution I have in calculation a numeric value and doesn't have to cast with Variant's get method.If want the result to always be the same type, then either use the explicit type or auto (though clearly auto is having some issues right now, so it might be best to avoid it if you're returning stuff that differs in type and needs to be converted). If you want the result to differ in type depending on the value returned, then you need Variant in order to simulate dynamic typing. I'm not quite sure what you're trying to do with your code, but if you use Variant, you'll need to use get or coerce to get its value from it, which it doesn't sound like what you want to do. If that's the case, then your get function needs to always return the same type - be it int or float or double or whatever, and you might as well just use the explicit type rather than auto, since it's a primitive type, not a complicated, templated one (which is the main reason to use auto for the return type of a function). - Jonathan M Davis
Sep 11 2012
On Tuesday, 11 September 2012 at 21:31:17 UTC, Namespace wrote:On Tuesday, 11 September 2012 at 21:13:02 UTC, bearophile wrote:Just this one. You can use an anonymous union in your Num struct, so you can write "obj.ivalue" rather than obj._num.ivalue": struct Num { private: final enum Type { None, Float, Int } union { float fvalue; int ivalue; } Type _type; .... GrahamNamespace:Sure that is the first i will do tomorrow. But so far no suggestions?I have this code, but it works not as expected: http://dpaste.dzfl.pl/6ce5b4ddI suggest to file a bug: auto foo(bool b) { final switch (b) { case true: return 10; case false: return 20.0; } } void main() { import std.stdio: writeln; writeln(foo(true)); writeln(foo(false)); } The acceptable results are a compile-time error for type mismatch, or a conversion of both literals to double. Probably the second is better. But a silent bit-level cast is not acceptable. Bye, bearophile
Sep 11 2012