digitalmars.D - Add support implicit conversion between types
- ilya-stromberg (37/37) Sep 06 2013 Do you have any plans to support implicit conversion between
- Benjamin Thaut (6/39) Sep 06 2013 I also made almost the same suggestion some time ago. I would support a
- Peter Alexander (4/6) Sep 06 2013 Implicit conversions open up a whole can of worms for the sake of
- Dicebot (4/7) Sep 06 2013 Agreed. It was quite common source of troubles in my C++ days and
- Benjamin Thaut (5/12) Sep 06 2013 Its only a source of troubles in C++ because it is the default behavior....
- ilya-stromberg (10/26) Sep 06 2013 Totally agree. The default implicit conversion in C++ is a
- Peter Alexander (4/8) Sep 06 2013 It's not just that single arg constructors are by default
- Dicebot (7/11) Sep 06 2013 Probably. But what is the gain? `foo(Foo(5))` looks better than
- Benjamin Thaut (4/14) Sep 06 2013 Try implementing a custom string class in D that does not depend on the
- Peter Alexander (5/19) Sep 07 2013 Could you not just implement a .str property that does the
- ilya-stromberg (25/29) Sep 06 2013 For exaple, for generic code:
- Dicebot (6/13) Sep 06 2013 So, what essentially is needed, is ability to implicitly convert
- ilya-stromberg (23/29) Sep 06 2013 Yes, the ability to implicitly convert literals of built-in types
- monarch_dodra (14/39) Sep 06 2013 Or just:
- H. S. Teoh (8/41) Sep 06 2013 I thought the usual D idiom was to write factorial(5) and
- ilya-stromberg (13/33) Sep 06 2013 No, I have the error:
- Dicebot (3/14) Sep 06 2013 Yeah, this one, contrary, seems to be really crucial feature
- ilya-stromberg (3/9) Sep 06 2013 Yes, I agree. It solves problem of the difference between
- H. S. Teoh (7/42) Sep 06 2013 Hmm, I see. This is an unfortunate limitation. In C++, writing int(123)
- Dmitry Olshansky (4/42) Sep 06 2013 I swear I've seen a pull request that enables it.
- Simen Kjaeraas (8/49) Sep 07 2013 3)
- H. S. Teoh (13/52) Sep 06 2013 [...]
- ilya-stromberg (9/19) Sep 06 2013 I use:
- H. S. Teoh (15/37) Sep 06 2013 I checked the disassembly for cast(T)5 for T==int and T==BigInt. Seems
- deadalnix (3/11) Sep 06 2013 This is very convenient when dealing with unknown types. Think
- ilya-stromberg (12/24) Sep 06 2013 In a few cases it's really useful.
- deadalnix (4/11) Sep 06 2013 I think we should be able to do it, but in unconvenient ways.
- Benjamin Thaut (3/13) Sep 06 2013 But that doesn't work for construction. Also its not possible to do it
- Flamaros (6/43) Sep 06 2013 It's difficult to never forget the "explicit" keyword in c++, and
- ilya-stromberg (4/8) Sep 06 2013 Yes. I sugest keep current D bechavior by default, but add
- deadalnix (3/13) Sep 06 2013 You don't want a keyword for that. Something obscure and ugly is
- ilya-stromberg (7/9) Sep 06 2013 C# have operator overloading for this.
- Simen Kjaeraas (13/22) Sep 07 2013 It's a bit weird in D though, as operators are instance methods, and
- ilya-stromberg (15/26) Sep 07 2013 Yes, "opImplicitCastFrom" looks better. I didn't know about
- Simen Kjaeraas (8/21) Sep 08 2013 http://s3.amazonaws.com/dconf2007/WalterAndrei.pdf
- Jonathan M Davis (8/52) Sep 06 2013 Personally, I think that this is opening a whole can of worms that shoul...
- monarch_dodra (9/21) Sep 06 2013 The problem with "alias this" is that it was designed to emulate
- Maxim Fomin (16/41) Sep 07 2013 Actually D has this feature for classes:
- monarch_dodra (2/17) Sep 07 2013 I don't see the rationale for it working for classes at all!
- Ramon (9/9) Sep 07 2013 I understand and support Kenjis request (linked in this thread)
Do you have any plans to support implicit conversion between types? I have some code like this: struct Foo { this(int i) { //do something useful } } void bar(Foo f) { //do something else } void main() { Foo f = 5;//works bar(f);//works bar(Foo(5));//works bar(5);//Error: function app.bar (Foo f) is not callable using argument types (int) } So, D can't use constructor to convert "int" to "Foo" implicitly. Can we add "implicit" keyword to allow do this: struct Foo { implicit this(int i) { //do something useful } } C++ allows this, but have "explicit" keyword. implicit and explicit cases.
Sep 06 2013
Am 06.09.2013 12:33, schrieb ilya-stromberg:Do you have any plans to support implicit conversion between types? I have some code like this: struct Foo { this(int i) { //do something useful } } void bar(Foo f) { //do something else } void main() { Foo f = 5;//works bar(f);//works bar(Foo(5));//works bar(5);//Error: function app.bar (Foo f) is not callable using argument types (int) } So, D can't use constructor to convert "int" to "Foo" implicitly. Can we add "implicit" keyword to allow do this: struct Foo { implicit this(int i) { //do something useful } } C++ allows this, but have "explicit" keyword. and explicit cases.I also made almost the same suggestion some time ago. I would support a feature like this. -- Kind Regards Benjamin Thaut
Sep 06 2013
On Friday, 6 September 2013 at 10:33:07 UTC, ilya-stromberg wrote:Do you have any plans to support implicit conversion between types?Implicit conversions open up a whole can of worms for the sake of a small amount of convenience. I'm not sure it's a fair trade.
Sep 06 2013
On Friday, 6 September 2013 at 11:04:31 UTC, Peter Alexander wrote:Implicit conversions open up a whole can of worms for the sake of a small amount of convenience. I'm not sure it's a fair trade.Agreed. It was quite common source of troubles in my C++ days and have never offered much convenience.
Sep 06 2013
Am 06.09.2013 13:27, schrieb Dicebot:On Friday, 6 September 2013 at 11:04:31 UTC, Peter Alexander wrote:Its only a source of troubles in C++ because it is the default behavior. But if you design a library it can make the usage of your api easier and also you have a few more options to stay backwards compatible with your old api.Implicit conversions open up a whole can of worms for the sake of a small amount of convenience. I'm not sure it's a fair trade.Agreed. It was quite common source of troubles in my C++ days and have never offered much convenience.
Sep 06 2013
On Friday, 6 September 2013 at 11:32:11 UTC, Benjamin Thaut wrote:Am 06.09.2013 13:27, schrieb Dicebot:Totally agree. The default implicit conversion in C++ is a mistake. The conversion must be explicit by default (like in D now). The programmer should use implicit conversion ONLY IF IT SAFE (like ftom "int" to "long"). For any other cases programmer should use explicit conversion (default). conversions by default and ability to explicitly add implicit conversion. And I never had problems with it.On Friday, 6 September 2013 at 11:04:31 UTC, Peter Alexander wrote:Its only a source of troubles in C++ because it is the default behavior. But if you design a library it can make the usage of your api easier and also you have a few more options to stay backwards compatible with your old api.Implicit conversions open up a whole can of worms for the sake of a small amount of convenience. I'm not sure it's a fair trade.Agreed. It was quite common source of troubles in my C++ days and have never offered much convenience.
Sep 06 2013
On Friday, 6 September 2013 at 11:32:11 UTC, Benjamin Thaut wrote:Its only a source of troubles in C++ because it is the default behavior. But if you design a library it can make the usage of your api easier and also you have a few more options to stay backwards compatible with your old api.It's not just that single arg constructors are by default implicit. Implicit conversions complicate things, like template argument deduction and overload resolution.
Sep 06 2013
On Friday, 6 September 2013 at 11:32:11 UTC, Benjamin Thaut wrote:Its only a source of troubles in C++ because it is the default behavior. But if you design a library it can make the usage of your api easier and also you have a few more options to stay backwards compatible with your old api.Probably. But what is the gain? `foo(Foo(5))` looks better than `foo(5)` to me in every possible way. For example, use case that justifies operator overloading (despite the danger) in my eyes is ability to replace built-in types with custom ones. What is the similar rationale for implicit conversion?
Sep 06 2013
Am 06.09.2013 15:01, schrieb Dicebot:On Friday, 6 September 2013 at 11:32:11 UTC, Benjamin Thaut wrote:Try implementing a custom string class in D that does not depend on the GC and you will know. Your code will be littered with explict constructions of strings, which makes it look totally ugly.Its only a source of troubles in C++ because it is the default behavior. But if you design a library it can make the usage of your api easier and also you have a few more options to stay backwards compatible with your old api.Probably. But what is the gain? `foo(Foo(5))` looks better than `foo(5)` to me in every possible way. For example, use case that justifies operator overloading (despite the danger) in my eyes is ability to replace built-in types with custom ones. What is the similar rationale for implicit conversion?
Sep 06 2013
On Friday, 6 September 2013 at 13:15:21 UTC, Benjamin Thaut wrote:Am 06.09.2013 15:01, schrieb Dicebot:Could you not just implement a .str property that does the conversion? Surely littering code with .str isn't too ugly? I understand the desire for it, but implicit coercions truly are evil.Probably. But what is the gain? `foo(Foo(5))` looks better than `foo(5)` to me in every possible way. For example, use case that justifies operator overloading (despite the danger) in my eyes is ability to replace built-in types with custom ones. What is the similar rationale for implicit conversion?Try implementing a custom string class in D that does not depend on the GC and you will know. Your code will be littered with explict constructions of strings, which makes it look totally ugly.
Sep 07 2013
On Friday, 6 September 2013 at 13:01:14 UTC, Dicebot wrote:For example, use case that justifies operator overloading (despite the danger) in my eyes is ability to replace built-in types with custom ones. What is the similar rationale for implicit conversion?For exaple, for generic code: T factorial(T)(T number) { return number <= 1 ? 1 : number * factorial!T(number - 1); } void main() { //works: factorial!int(5); //doesn't work: factorial!BigInt(5); } It can be critical for more complex cases, when you call one generic function from another one, like this: unittest { alias TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong, BigInt) IntegralTypeList; foreach(T; IntegralTypeList) { assert(factorial!T(3) == 6);//Error: factorial (BigInt number) is not callable using argument types (int) } }
Sep 06 2013
On Friday, 6 September 2013 at 13:21:44 UTC, ilya-stromberg wrote:On Friday, 6 September 2013 at 13:01:14 UTC, Dicebot wrote:So, what essentially is needed, is ability to implicitly convert literals of built-in types to user types, not any possible implicit conversion? I think allowing it with such restrictions can be reasonably clean.For example, use case that justifies operator overloading (despite the danger) in my eyes is ability to replace built-in types with custom ones. What is the similar rationale for implicit conversion?For exaple, for generic code: ...
Sep 06 2013
On Friday, 6 September 2013 at 13:30:26 UTC, Dicebot wrote:So, what essentially is needed, is ability to implicitly convert literals of built-in types to user types, not any possible implicit conversion? I think allowing it with such restrictions can be reasonably clean.Yes, the ability to implicitly convert literals of built-in types to user types is REALLY needed. The 2-nd error from "factorial" example import std.bigint; void main() { assert(factorial!BigInt(BigInt(3)) == 6); //Error: incompatible types for ((1) : (number.opBinary(factorial(number.opBinary(1))))): 'int' and 'BigInt' } The correct factorial implementation is: T factorial(T)(T number) { enum T one = 1; return number <= one ? one : number * factorial!T(number - one); } It's complicated, how do you think?not any possible implicit conversion?I didn't think about yet. May be you are right, but I think it can be also useful. For example, if you can't change user-defined type.
Sep 06 2013
On Friday, 6 September 2013 at 13:50:25 UTC, ilya-stromberg wrote:On Friday, 6 September 2013 at 13:30:26 UTC, Dicebot wrote:Or just: //---- import std.bigint; T factorial(T)(T number) { return number <= 1 ? T(1) : number * factorial!T(number - 1); } //---- The problem though is that this requires "uniform construction", which we don't have yet: http://d.puremagic.com/issues/show_bug.cgi?id=9112So, what essentially is needed, is ability to implicitly convert literals of built-in types to user types, not any possible implicit conversion? I think allowing it with such restrictions can be reasonably clean.Yes, the ability to implicitly convert literals of built-in types to user types is REALLY needed. The 2-nd error from "factorial" example import std.bigint; void main() { assert(factorial!BigInt(BigInt(3)) == 6); //Error: incompatible types for ((1) : (number.opBinary(factorial(number.opBinary(1))))): 'int' and 'BigInt' } The correct factorial implementation is: T factorial(T)(T number) { enum T one = 1; return number <= one ? one : number * factorial!T(number - one); }
Sep 06 2013
On Fri, Sep 06, 2013 at 03:21:42PM +0200, ilya-stromberg wrote:On Friday, 6 September 2013 at 13:01:14 UTC, Dicebot wrote:I thought the usual D idiom was to write factorial(5) and factorial(BigInt(5)) and let the compiler figure out which template instance you wanted?For example, use case that justifies operator overloading (despite the danger) in my eyes is ability to replace built-in types with custom ones. What is the similar rationale for implicit conversion?For exaple, for generic code: T factorial(T)(T number) { return number <= 1 ? 1 : number * factorial!T(number - 1); } void main() { //works: factorial!int(5); //doesn't work: factorial!BigInt(5); }It can be critical for more complex cases, when you call one generic function from another one, like this: unittest { alias TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong, BigInt) IntegralTypeList; foreach(T; IntegralTypeList) { assert(factorial!T(3) == 6);//Error: factorial (BigInt number) is not callable using argument types (int)You could just write factorial(T(3)) ? T -- Prosperity breeds contempt, and poverty breeds consent. -- Suck.com
Sep 06 2013
On Friday, 6 September 2013 at 14:26:17 UTC, H. S. Teoh wrote:I thought the usual D idiom was to write factorial(5) and factorial(BigInt(5)) and let the compiler figure out which template instance you wanted?Yes, but it isn't always possible.No, I have the error: Error: function expected before (), not byte of type byte Error: function expected before (), not ubyte of type ubyte Error: function expected before (), not short of type short Error: function expected before (), not ushort of type ushort Error: function expected before (), not int of type int Error: function expected before (), not uint of type uint Error: function expected before (), not long of type long Error: function expected before (), not ulong of type ulong As monarch_dodra pointed above, we haven't got "uniform construction" support.It can be critical for more complex cases, when you call one generic function from another one, like this: unittest { alias TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong, BigInt) IntegralTypeList; foreach(T; IntegralTypeList) { assert(factorial!T(3) == 6);//Error: factorial (BigInt number) is not callable using argument types (int)You could just write factorial(T(3)) ?
Sep 06 2013
On Friday, 6 September 2013 at 15:14:50 UTC, ilya-stromberg wrote:No, I have the error: Error: function expected before (), not byte of type byte Error: function expected before (), not ubyte of type ubyte Error: function expected before (), not short of type short Error: function expected before (), not ushort of type ushort Error: function expected before (), not int of type int Error: function expected before (), not uint of type uint Error: function expected before (), not long of type long Error: function expected before (), not ulong of type ulong As monarch_dodra pointed above, we haven't got "uniform construction" support.Yeah, this one, contrary, seems to be really crucial feature lacking.
Sep 06 2013
On Friday, 6 September 2013 at 15:47:27 UTC, Dicebot wrote:On Friday, 6 September 2013 at 15:14:50 UTC, ilya-stromberg wrote:Yes, I agree. It solves problem of the difference between built-in and user-defined types for explicit cast.As monarch_dodra pointed above, we haven't got "uniform construction" support.Yeah, this one, contrary, seems to be really crucial feature lacking.
Sep 06 2013
On Fri, Sep 06, 2013 at 05:14:48PM +0200, ilya-stromberg wrote:On Friday, 6 September 2013 at 14:26:17 UTC, H. S. Teoh wrote:Hmm, I see. This is an unfortunate limitation. In C++, writing int(123) actually works. Looks like D is lacking in this area. :-( T -- Answer: Because it breaks the logical sequence of discussion. Question: Why is top posting bad?I thought the usual D idiom was to write factorial(5) and factorial(BigInt(5)) and let the compiler figure out which template instance you wanted?Yes, but it isn't always possible.No, I have the error: Error: function expected before (), not byte of type byte Error: function expected before (), not ubyte of type ubyte Error: function expected before (), not short of type short Error: function expected before (), not ushort of type ushort Error: function expected before (), not int of type int Error: function expected before (), not uint of type uint Error: function expected before (), not long of type long Error: function expected before (), not ulong of type ulong As monarch_dodra pointed above, we haven't got "uniform construction" support.It can be critical for more complex cases, when you call one generic function from another one, like this: unittest { alias TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong, BigInt) IntegralTypeList; foreach(T; IntegralTypeList) { assert(factorial!T(3) == 6);//Error: factorial (BigInt number) is not callable using argument types (int)You could just write factorial(T(3)) ?
Sep 06 2013
06-Sep-2013 21:05, H. S. Teoh пишет:On Fri, Sep 06, 2013 at 05:14:48PM +0200, ilya-stromberg wrote:I swear I've seen a pull request that enables it. -- Dmitry OlshanskyOn Friday, 6 September 2013 at 14:26:17 UTC, H. S. Teoh wrote:Hmm, I see. This is an unfortunate limitation. In C++, writing int(123) actually works. Looks like D is lacking in this area. :-(I thought the usual D idiom was to write factorial(5) and factorial(BigInt(5)) and let the compiler figure out which template instance you wanted?Yes, but it isn't always possible.No, I have the error: Error: function expected before (), not byte of type byte Error: function expected before (), not ubyte of type ubyte Error: function expected before (), not short of type short Error: function expected before (), not ushort of type ushort Error: function expected before (), not int of type int Error: function expected before (), not uint of type uint Error: function expected before (), not long of type long Error: function expected before (), not ulong of type ulong As monarch_dodra pointed above, we haven't got "uniform construction" support.It can be critical for more complex cases, when you call one generic function from another one, like this: unittest { alias TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong, BigInt) IntegralTypeList; foreach(T; IntegralTypeList) { assert(factorial!T(3) == 6);//Error: factorial (BigInt number) is not callable using argument types (int)You could just write factorial(T(3)) ?
Sep 06 2013
On 2013-09-06, 19:12, Dmitry Olshansky wrote:06-Sep-2013 21:05, H. S. Teoh =D0=BF=D0=B8=D1=88=D0=B5=D1=82:On Fri, Sep 06, 2013 at 05:14:48PM +0200, ilya-stromberg wrote:On Friday, 6 September 2013 at 14:26:17 UTC, H. S. Teoh wrote:I thought the usual D idiom was to write factorial(5) and factorial(BigInt(5)) and let the compiler figure out which template=icinstance you wanted?Yes, but it isn't always possible.It can be critical for more complex cases, when you call one gener=3)Hmm, I see. This is an unfortunate limitation. In C++, writing int(12=No, I have the error: Error: function expected before (), not byte of type byte Error: function expected before (), not ubyte of type ubyte Error: function expected before (), not short of type short Error: function expected before (), not ushort of type ushort Error: function expected before (), not int of type int Error: function expected before (), not uint of type uint Error: function expected before (), not long of type long Error: function expected before (), not ulong of type ulong As monarch_dodra pointed above, we haven't got "uniform construction" support.function from another one, like this: unittest { alias TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong, BigInt) IntegralTypeList; foreach(T; IntegralTypeList) { assert(factorial!T(3) =3D=3D 6);//Error: factorial (BigInt number) is not callable using argument types (int)You could just write factorial(T(3)) ?This one? https://github.com/D-Programming-Language/dmd/pull/1356 It seems to be on its way. -- = Simenactually works. Looks like D is lacking in this area. :-(I swear I've seen a pull request that enables it.
Sep 07 2013
On Fri, Sep 06, 2013 at 10:05:47AM -0700, H. S. Teoh wrote:On Fri, Sep 06, 2013 at 05:14:48PM +0200, ilya-stromberg wrote:[...] Hmm, could this be a possible (though somewhat ugly) workaround? foreach (T; IntegralTypeList) { assert(factorial(to!T(3) == 6)); } AFAIK, if T==int, then std.conv.to should simply alias itself away. And it *should* be able to handle ctors that take the requisite type, I think. T -- "The number you have dialed is imaginary. Please rotate your phone 90 degrees and try again."On Friday, 6 September 2013 at 14:26:17 UTC, H. S. Teoh wrote:Hmm, I see. This is an unfortunate limitation. In C++, writing int(123) actually works. Looks like D is lacking in this area. :-(I thought the usual D idiom was to write factorial(5) and factorial(BigInt(5)) and let the compiler figure out which template instance you wanted?Yes, but it isn't always possible.No, I have the error: Error: function expected before (), not byte of type byte Error: function expected before (), not ubyte of type ubyte Error: function expected before (), not short of type short Error: function expected before (), not ushort of type ushort Error: function expected before (), not int of type int Error: function expected before (), not uint of type uint Error: function expected before (), not long of type long Error: function expected before (), not ulong of type ulong As monarch_dodra pointed above, we haven't got "uniform construction" support.It can be critical for more complex cases, when you call one generic function from another one, like this: unittest { alias TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong, BigInt) IntegralTypeList; foreach(T; IntegralTypeList) { assert(factorial!T(3) == 6);//Error: factorial (BigInt number) is not callable using argument types (int)You could just write factorial(T(3)) ?
Sep 06 2013
On Friday, 6 September 2013 at 17:15:03 UTC, H. S. Teoh wrote:Hmm, could this be a possible (though somewhat ugly) workaround? foreach (T; IntegralTypeList) { assert(factorial(to!T(3) == 6)); } AFAIK, if T==int, then std.conv.to should simply alias itself away. And it *should* be able to handle ctors that take the requisite type, I think.I use: foreach (T; IntegralTypeList) { assert(factorial(cast(T)3) == 6)); } I works, but looks a little strange. I belive that compiler should optimise this (do nothing), but I am not sure.
Sep 06 2013
On Fri, Sep 06, 2013 at 07:25:21PM +0200, ilya-stromberg wrote:On Friday, 6 September 2013 at 17:15:03 UTC, H. S. Teoh wrote:I checked the disassembly for cast(T)5 for T==int and T==BigInt. Seems the compiler is doing the "right thing" in both cases. For T==int, the compiler just loads 5 directly into the register; for T==BigInt, it calls the BigInt ctor with 5 as parameter to construct an instance of BigInt. So, this seems to work, even though it looks ugly. T -- A linguistics professor was lecturing to his class one day. "In English," he said, "A double negative forms a positive. In some languages, though, such as Russian, a double negative is still a negative. However, there is no language wherein a double positive can form a negative." A voice from the back of the room piped up, "Yeah, yeah."Hmm, could this be a possible (though somewhat ugly) workaround? foreach (T; IntegralTypeList) { assert(factorial(to!T(3) == 6)); } AFAIK, if T==int, then std.conv.to should simply alias itself away. And it *should* be able to handle ctors that take the requisite type, I think.I use: foreach (T; IntegralTypeList) { assert(factorial(cast(T)3) == 6)); } I works, but looks a little strange. I belive that compiler should optimise this (do nothing), but I am not sure.
Sep 06 2013
On Friday, 6 September 2013 at 13:01:14 UTC, Dicebot wrote:On Friday, 6 September 2013 at 11:32:11 UTC, Benjamin Thaut wrote:This is very convenient when dealing with unknown types. Think JSON manipulation for instance.Its only a source of troubles in C++ because it is the default behavior. But if you design a library it can make the usage of your api easier and also you have a few more options to stay backwards compatible with your old api.Probably. But what is the gain? `foo(Foo(5))` looks better than `foo(5)` to me in every possible way.
Sep 06 2013
On Friday, 6 September 2013 at 13:01:14 UTC, Dicebot wrote:On Friday, 6 September 2013 at 11:32:11 UTC, Benjamin Thaut wrote:In a few cases it's really useful. Assume that you have user-defined type, for example BigInt. You must implement A LOT OF "foo" functions which works only whith BigInt, like RSA, DSA and etc. For example, 100-500 different functions. Do you still want to write every time `foo(BigInt(5))`? (Remember: you have to use only BigInt). So, the short answer is the same as for operator overloading: in my eyes is ability to replace built-in types with custom ones. Yes, it can be dangerous, and we must to provide explicit cast by default. But in many cases it can simplify a life and a code.Its only a source of troubles in C++ because it is the default behavior. But if you design a library it can make the usage of your api easier and also you have a few more options to stay backwards compatible with your old api.Probably. But what is the gain? `foo(Foo(5))` looks better than `foo(5)` to me in every possible way. For example, use case that justifies operator overloading (despite the danger) in my eyes is ability to replace built-in types with custom ones. What is the similar rationale for implicit conversion?
Sep 06 2013
On Friday, 6 September 2013 at 11:04:31 UTC, Peter Alexander wrote:On Friday, 6 September 2013 at 10:33:07 UTC, ilya-stromberg wrote:I think we should be able to do it, but in unconvenient ways. Like alias this + a property.Do you have any plans to support implicit conversion between types?Implicit conversions open up a whole can of worms for the sake of a small amount of convenience. I'm not sure it's a fair trade.
Sep 06 2013
Am 06.09.2013 13:44, schrieb deadalnix:On Friday, 6 September 2013 at 11:04:31 UTC, Peter Alexander wrote:But that doesn't work for construction. Also its not possible to do it for primitive types (especially string comes to mind)On Friday, 6 September 2013 at 10:33:07 UTC, ilya-stromberg wrote:I think we should be able to do it, but in unconvenient ways. Like alias this + a property.Do you have any plans to support implicit conversion between types?Implicit conversions open up a whole can of worms for the sake of a small amount of convenience. I'm not sure it's a fair trade.
Sep 06 2013
On Friday, 6 September 2013 at 10:33:07 UTC, ilya-stromberg wrote:Do you have any plans to support implicit conversion between types? I have some code like this: struct Foo { this(int i) { //do something useful } } void bar(Foo f) { //do something else } void main() { Foo f = 5;//works bar(f);//works bar(Foo(5));//worksI think that the good way, to dobar(5);//Error: function app.bar (Foo f) is not callable using argument types (int) } So, D can't use constructor to convert "int" to "Foo" implicitly. Can we add "implicit" keyword to allow do this: struct Foo { implicit this(int i) { //do something useful } } C++ allows this, but have "explicit" keyword. implicit and explicit cases.It's difficult to never forget the "explicit" keyword in c++, and this little mistake can make you loose a lot of time. I prefer to only have explicit conversions with cast or constructors calls, that all make the code easier to understand.
Sep 06 2013
On Friday, 6 September 2013 at 13:25:37 UTC, Flamaros wrote:It's difficult to never forget the "explicit" keyword in c++, and this little mistake can make you loose a lot of time. I prefer to only have explicit conversions with cast or constructors calls, that all make the code easier to understand.Yes. I sugest keep current D bechavior by default, but add "implicit" keyword. It allows to add implicit cast only if it SAFE.
Sep 06 2013
On Friday, 6 September 2013 at 13:31:41 UTC, ilya-stromberg wrote:On Friday, 6 September 2013 at 13:25:37 UTC, Flamaros wrote:You don't want a keyword for that. Something obscure and ugly is required.It's difficult to never forget the "explicit" keyword in c++, and this little mistake can make you loose a lot of time. I prefer to only have explicit conversions with cast or constructors calls, that all make the code easier to understand.Yes. I sugest keep current D bechavior by default, but add "implicit" keyword. It allows to add implicit cast only if it SAFE.
Sep 06 2013
On Friday, 6 September 2013 at 13:39:20 UTC, deadalnix wrote:You don't want a keyword for that. Something obscure and ugly is required.We can use, for example, "opImplicitRightCast" struct Foo { Foo opImplicitRightCast(T)(T from); }
Sep 06 2013
On 2013-09-06, 15:57, ilya-stromberg wrote:On Friday, 6 September 2013 at 13:39:20 UTC, deadalnix wrote:You don't want a keyword for that. Something obscure and ugly is =It's a bit weird in D though, as operators are instance methods, and opImplicitRightCast (or opImplicitCastFrom, which is the name used in discussions before, see WalterAndrei.pdf from back when dinosaurs roamed= = the earth) should definitely not be an instance method but a static one. That said, I belive opImplicitCastFrom is The Right Solution=E2=84=A2. I= t's = explicit, it's a bit ugly, but not so much it hurts. -- = Simenrequired.We can use, for example, "opImplicitRightCast" struct Foo { Foo opImplicitRightCast(T)(T from); }
Sep 07 2013
On Saturday, 7 September 2013 at 13:02:39 UTC, Simen Kjaeraas wrote:It's a bit weird in D though, as operators are instance methods, and opImplicitRightCast (or opImplicitCastFrom, which is the name used in discussions before, see WalterAndrei.pdf from back when dinosaurs roamed the earth) should definitely not be an instance method but a static one. That said, I belive opImplicitCastFrom is The Right Solution™. It's explicit, it's a bit ugly, but not so much it hurts.Yes, "opImplicitCastFrom" looks better. I didn't know about "WalterAndrei.pdf" file. Can you give me a link to the file? It's intresting to read. class Foo { public Foo(int temp) { } public static implicit operator Foo(int temp) { return new Foo(temp); } } So, I agree, the "opImplicitCastFrom" should be also static.
Sep 07 2013
On 2013-09-07, 15:19, ilya-stromberg wrote:On Saturday, 7 September 2013 at 13:02:39 UTC, Simen Kjaeraas wrote:It's a bit weird in D though, as operators are instance methods, and opImplicitRightCast (or opImplicitCastFrom, which is the name used in=discussions before, see WalterAndrei.pdf from back when dinosaurs =. It's =roamed the earth) should definitely not be an instance method but a static one. That said, I belive opImplicitCastFrom is The Right Solution=E2=84=A2=explicit, it's a bit ugly, but not so much it hurts.Yes, "opImplicitCastFrom" looks better. I didn't know about ="WalterAndrei.pdf" file. Can you give me a link to the file? It's =intresting to read.http://s3.amazonaws.com/dconf2007/WalterAndrei.pdf It's from the D conference back in 2007, as the URL indicates. opImplicitCastFrom is mentioned on page 22. It's kinda interesting to see what was happening back then and how things have progressed. -- = Simen
Sep 08 2013
On Friday, September 06, 2013 12:33:05 ilya-stromberg wrote:Do you have any plans to support implicit conversion between types? I have some code like this: struct Foo { this(int i) { //do something useful } } void bar(Foo f) { //do something else } void main() { Foo f = 5;//works bar(f);//works bar(Foo(5));//works bar(5);//Error: function app.bar (Foo f) is not callable using argument types (int) } So, D can't use constructor to convert "int" to "Foo" implicitly. Can we add "implicit" keyword to allow do this: struct Foo { implicit this(int i) { //do something useful } } C++ allows this, but have "explicit" keyword. implicit and explicit cases.Personally, I think that this is opening a whole can of worms that should never be opened. alias this already causes enough trouble for stuff like templates (primarily because it becomes far too easy to pass a template constraint and yet fail to work in the actual code). It's ultimately way cleaner and far less bug-prone to disallow this sort of implicit conversion, especially when so much D code is generic code. - Jonathan M Davis
Sep 06 2013
On Friday, 6 September 2013 at 17:49:04 UTC, Jonathan M Davis wrote:Personally, I think that this is opening a whole can of worms that should never be opened. alias this already causes enough trouble for stuff like templates (primarily because it becomes far too easy to pass a template constraint and yet fail to work in the actual code). It's ultimately way cleaner and far less bug-prone to disallow this sort of implicit conversion, especially when so much D code is generic code. - Jonathan M DavisThe problem with "alias this" is that it was designed to emulate inheritance, but was *diverted*, specifically, to emulate "implicit casting instead". I think the results speak for themselves how well that worked... As a matter of fact, there are more than a few classes where I wish we could deprecate the static alias, and re-force explicit cast.
Sep 06 2013
On Friday, 6 September 2013 at 10:33:07 UTC, ilya-stromberg wrote:Do you have any plans to support implicit conversion between types? I have some code like this: struct Foo { this(int i) { //do something useful } } void bar(Foo f) { //do something else } void main() { Foo f = 5;//works bar(f);//works bar(Foo(5));//works bar(5);//Error: function app.bar (Foo f) is not callable using argument types (int) }Actually D has this feature for classes: class A { this(int) {} } void foo(A a ...) {} void main() { foo(5); } This compiles and runs as expected. By the way, the code was fixed recently - before 2.063 this was allocating class on stack (so in D there were some kind of scoped stack classes), now this allocates on heap as usual. I don't see the rationale behind not working with structs.
Sep 07 2013
On Saturday, 7 September 2013 at 19:37:28 UTC, Maxim Fomin wrote:Actually D has this feature for classes: class A { this(int) {} } void foo(A a ...) {} void main() { foo(5); } This compiles and runs as expected. By the way, the code was fixed recently - before 2.063 this was allocating class on stack (so in D there were some kind of scoped stack classes), now this allocates on heap as usual. I don't see the rationale behind not working with structs.I don't see the rationale for it working for classes at all!
Sep 07 2013
I understand and support Kenjis request (linked in this thread) in the "no casting, though" version. approach and measure. Whatever feature is introducing inconsistencies is almost never worth it. We do have explicit conversion. If anyone feels that to look ugly he should ask what's worse, language inconsistencies or looks. A+ -R
Sep 07 2013