View mode: basic / threaded / horizontal-split · Log in · Help
October 19, 2012
Implicit Conversions in Struct Construction
Hello,
  I have been playing around with templated range. I am not quite 
sure why the following code does not work:

template isIntLike(T) {
	enum isIntLike = is(typeof({
		T t = 0;
		t = t+t;
		// More if needed
	}));
}

auto fib(T = int)() if (isIntLike!T) {
	struct Fib {
		T a, b;
		
		T front() {return b;}
		bool empty() {return false;}
		
		void popFront() {
			T c = a+b;
			a = b;
			b = c;
		}
	}
	return Fib(0, 1);
}

This code does not work if I call fib!BigInt(). The compiler 
complains that 0 cannot be implicitly converted into a BigInt. It 
is right of course, but BigInt has a constructor accepting a 
long, so shouldn't this work anyway? What is the correct way to 
write this function?

Thank you all for your time,
Michael
October 19, 2012
Re: Implicit Conversions in Struct Construction
On Friday, October 19, 2012 05:44:10 Michael wrote:
> Hello,
>    I have been playing around with templated range. I am not quite
> sure why the following code does not work:
> 
> template isIntLike(T) {
> 	enum isIntLike = is(typeof({
> 		T t = 0;
> 		t = t+t;
> 		// More if needed
> 	}));
> }
> 
> auto fib(T = int)() if (isIntLike!T) {
> 	struct Fib {
> 		T a, b;
> 
> 		T front() {return b;}
> 		bool empty() {return false;}
> 
> 		void popFront() {
> 			T c = a+b;
> 			a = b;
> 			b = c;
> 		}
> 	}
> 	return Fib(0, 1);
> }
> 
> This code does not work if I call fib!BigInt(). The compiler
> complains that 0 cannot be implicitly converted into a BigInt. It
> is right of course, but BigInt has a constructor accepting a
> long, so shouldn't this work anyway? What is the correct way to
> write this function?

Constructors aren't implicitly called in D like they are in C++. If you have a 
function which takes a BigInt, it won't accept anything except a BigInt and 
something which implicitly converts to a BigInt (which would mean that the 
type had an alias this which converted it to BigInt). So, Fib(0, 1) will never 
work for Fib!BigInt. It would require Fib(BigInt(0), BigInt(1)), which you 
obviously can't do in generic code. However, you can use std.conv.to to do the 
conversion, so it becomes Fib(to!T(0), to!T(1)), and that should work (to will 
call the constructor if the constructor accepts the type that you're giving 
it). But if you do that, you should probably adjust isIntLike to also test 
that to!T(0) works.

- Jonathan M Davis
October 19, 2012
Re: Implicit Conversions in Struct Construction
On 10/18/2012 08:44 PM, Michael wrote:

> auto fib(T = int)() if (isIntLike!T) {
> struct Fib {
> T a, b;

// ...

> return Fib(0, 1);
> }
>
> This code does not work if I call fib!BigInt(). The compiler complains
> that 0 cannot be implicitly converted into a BigInt. It is right of
> course, but BigInt has a constructor accepting a long, so shouldn't this
> work anyway? What is the correct way to write this function?

Explicit conversion works:

    return Fib(T(0), T(1));

Ali
October 19, 2012
Re: Implicit Conversions in Struct Construction
On Thursday, October 18, 2012 20:55:12 Ali Çehreli wrote:
> Explicit conversion works:
> 
>      return Fib(T(0), T(1));

Except that that won't work for int or other built-in types, because they lack 
constructors. What you need is std.conv.to.

- Jonathan M Davis
October 19, 2012
Re: Implicit Conversions in Struct Construction
Jonathan M Davis:

> Except that that won't work for int or other built-in types, 
> because they lack constructors.

Isn't it possible to modify D and add constructors to built-in 
types?

int(10)

Bye,
bearophile
October 19, 2012
Re: Implicit Conversions in Struct Construction
On Friday, October 19, 2012 10:59:07 bearophile wrote:
> Jonathan M Davis:
> > Except that that won't work for int or other built-in types,
> > because they lack constructors.
> 
> Isn't it possible to modify D and add constructors to built-in
> types?
> 
> int(10)

Of course, it would be possible. Whether Walter would agree to though, I have 
no idea. C++ allows it only because it allows you to use the cast operator in 
reverse - i.e. int(10) is identical to (int)10 - though it wouldn't need it in 
the OP's example, because it would do the implicit conversion.

What I'd like to see even more is the ability to do

auto i = new int(10);

which would be particularly useful with immutable, since right now, it's 
impossible to create an immutable pointer to int with a value of anything 
other than 0 without casting.

- Jonathan M Davis
October 19, 2012
Re: Implicit Conversions in Struct Construction
On Friday, 19 October 2012 at 09:36:14 UTC, Jonathan M Davis 
wrote:
> On Friday, October 19, 2012 10:59:07 bearophile wrote:
>> Jonathan M Davis:
>> > Except that that won't work for int or other built-in types,
>> > because they lack constructors.
>> 
>> Isn't it possible to modify D and add constructors to built-in
>> types?
>> 
>> int(10)
>
> Of course, it would be possible. Whether Walter would agree to 
> though, I have
> no idea. C++ allows it only because it allows you to use the 
> cast operator in
> reverse - i.e. int(10) is identical to (int)10 - though it 
> wouldn't need it in
> the OP's example, because it would do the implicit conversion.
>
> What I'd like to see even more is the ability to do
>
> auto i = new int(10);
>
> which would be particularly useful with immutable, since right 
> now, it's
> impossible to create an immutable pointer to int with a value 
> of anything
> other than 0 without casting.
>
> - Jonathan M Davis

You can use the array.ptr "trick" (or exploit):

void main()
{
  immutable int a = 5;
  immutable(int)* p1 = [a].ptr;
  immutable(int*) p2 = [a].ptr;
}

That said, it is ugly as sin, and "new int(5)" should definitely 
supported.

Same thing with structs actually, which can be "agglomerate 
constructed", or "default copy constructed" : If you can write 
"auto a = T(x);" you should be able to write "auto p = new T(x)";
Top | Discussion index | About this forum | D home