September 06, 2013
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
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
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
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
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
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
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
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
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
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