September 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:
> >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);
> }

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?


> 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
September 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.

>> 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)) ?

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.
September 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.
September 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:
> >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.
> 
> >>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)) ?
> 
> 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.

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?
September 06, 2013
06-Sep-2013 21:05, H. S. Teoh пишет:
> 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
>>> instance you wanted?
>>
>> Yes, but it isn't always possible.
>>
>>>> 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)) ?
>>
>> 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.
>
> Hmm, I see. This is an unfortunate limitation. In C++, writing int(123)
> actually works. Looks like D is lacking in this area. :-(

I swear I've seen a pull request that enables it.


-- 
Dmitry Olshansky
September 06, 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:
> > 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.
> > 
> > >>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)) ?
> > 
> > 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.
> 
> Hmm, I see. This is an unfortunate limitation. In C++, writing int(123)
> actually works. Looks like D is lacking in this area. :-(
[...]

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."
September 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:
>> As monarch_dodra pointed above, we haven't got "uniform construction" support.
>
> Yeah, this one, contrary, seems to be really crucial feature lacking.

Yes, I agree. It solves problem of the difference between built-in and user-defined types for explicit cast.
September 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.
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.
>
> 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?

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.
September 06, 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.
> C# doesn't allow this, but have operator overloading for both
> 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