September 06, 2013 Re: Add support implicit conversion between types | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dicebot | Am 06.09.2013 15:01, schrieb Dicebot:
> 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?
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.
|
September 06, 2013 Re: Add support implicit conversion between types | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dicebot | 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)
}
}
|
September 06, 2013 Re: Add support implicit conversion between types | ||||
---|---|---|---|---|
| ||||
Posted in reply to ilya-stromberg | 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 I think that the good way, to do > 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. > C# doesn't allow this, but have operator overloading for both 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. |
September 06, 2013 Re: Add support implicit conversion between types | ||||
---|---|---|---|---|
| ||||
Posted in reply to ilya-stromberg | 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:
>> 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:
> ...
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.
|
September 06, 2013 Re: Add support implicit conversion between types | ||||
---|---|---|---|---|
| ||||
Posted in reply to Flamaros | 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.
|
September 06, 2013 Re: Add support implicit conversion between types | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dicebot | 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:
>> 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.
>
This is very convenient when dealing with unknown types. Think JSON manipulation for instance.
|
September 06, 2013 Re: Add support implicit conversion between types | ||||
---|---|---|---|---|
| ||||
Posted in reply to ilya-stromberg | 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:
>> 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.
You don't want a keyword for that. Something obscure and ugly is required.
|
September 06, 2013 Re: Add support implicit conversion between types | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dicebot | 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. |
September 06, 2013 Re: Add support implicit conversion between types | ||||
---|---|---|---|---|
| ||||
Posted in reply to deadalnix | 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.
C# have operator overloading for this.
We can use, for example, "opImplicitRightCast"
struct Foo
{
Foo opImplicitRightCast(T)(T from);
}
|
September 06, 2013 Re: Add support implicit conversion between types | ||||
---|---|---|---|---|
| ||||
Posted in reply to ilya-stromberg | 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: >> 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); > } 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=9112 |
Copyright © 1999-2021 by the D Language Foundation