Thread overview
Re: toImpl deprecated, use opCast instead?
Jun 07, 2012
Jens Mueller
Jun 08, 2012
Manu
Jun 08, 2012
Peter Alexander
Jun 08, 2012
Jonathan M Davis
Jun 08, 2012
Jens Mueller
Jun 10, 2012
timotheecour
Jun 10, 2012
Jonathan M Davis
Jun 11, 2012
Manu
Jun 11, 2012
Era Scarecrow
Jun 11, 2012
Jonathan M Davis
June 07, 2012
Manu wrote:
> Seriously?
> 
> I perceive to!T and cast(T) as fundamentally different operations. How can
> opCast correctly perform the role of to! ?
> cast() is a low level type cast, to! implies a conversion of some kind. If
> you have a pointer type, I assume cast to operate on the pointer, and to!
> to perform a conversion of the thing it represents.
> 
> to!int("12345")  or  cast(int)"12345"
> to!JSONValue(obj)  or  cast(JSONValue)obj
> cast(string)obj  <- appears to be a primitive cast operator, communicates
> nothing to me about the expected format of the string produced
> 
> The cast approach feel really wrong to me...
> 
> I need to do conversion between some fairly complex types. to! feels
> appropriate, but cast() just seems weird...
> Have I missed something?

I think the passage you are referring to applies only when converting
from a user defined type to a built-in type.
If you have user defined types only the right approach is to define a
constructor in the target type I think.
Something like this:

struct A {}
struct B {
	this(A a)
	{
	}
}

to!B(A); // will use B's constructor

I don't know what to do if you have no control over B (besides opCast or providing a specialized to! template).

Does this help?

Jens
June 08, 2012
On 7 June 2012 17:09, Jens Mueller <jens.k.mueller@gmx.de> wrote:

> Manu wrote:
> > Seriously?
> >
> > I perceive to!T and cast(T) as fundamentally different operations. How
> can
> > opCast correctly perform the role of to! ?
> > cast() is a low level type cast, to! implies a conversion of some kind.
> If
> > you have a pointer type, I assume cast to operate on the pointer, and to! to perform a conversion of the thing it represents.
> >
> > to!int("12345")  or  cast(int)"12345"
> > to!JSONValue(obj)  or  cast(JSONValue)obj
> > cast(string)obj  <- appears to be a primitive cast operator, communicates
> > nothing to me about the expected format of the string produced
> >
> > The cast approach feel really wrong to me...
> >
> > I need to do conversion between some fairly complex types. to! feels
> > appropriate, but cast() just seems weird...
> > Have I missed something?
>
> I think the passage you are referring to applies only when converting
> from a user defined type to a built-in type.
> If you have user defined types only the right approach is to define a
> constructor in the target type I think.
> Something like this:
>
> struct A {}
> struct B {
>        this(A a)
>        {
>        }
> }
>
> to!B(A); // will use B's constructor
>
> I don't know what to do if you have no control over B (besides opCast or providing a specialized to! template).
>

I have no control over B.
I thought the idea of toImpl() was to avoid having to specialise to! ?
I generally liked the idea, except the name toImpl seems odd (what's
'implicit' about an explicit conversion function?)


June 08, 2012
On Friday, 8 June 2012 at 07:29:21 UTC, Manu wrote:
> I generally liked the idea, except the name toImpl seems odd (what's
> 'implicit' about an explicit conversion function?)

I believe it stands for "implementation", not "implicit".
June 08, 2012
On Thursday, June 07, 2012 16:47:08 Manu wrote:
> Seriously?
> 
> I perceive to!T and cast(T) as fundamentally different operations. How can
> opCast correctly perform the role of to! ?
> cast() is a low level type cast, to! implies a conversion of some kind. If
> you have a pointer type, I assume cast to operate on the pointer, and to!
> to perform a conversion of the thing it represents.
> 
> to!int("12345")  or  cast(int)"12345"
> to!JSONValue(obj)  or  cast(JSONValue)obj
> cast(string)obj  <- appears to be a primitive cast operator, communicates
> nothing to me about the expected format of the string produced
> 
> The cast approach feel really wrong to me...
> 
> I need to do conversion between some fairly complex types. to! feels
> appropriate, but cast() just seems weird...
> Have I missed something?

As the documentation says:

$(RED Deprecated. It will be removed in August 2012. Please define $(D opCast)
      for user-defined types instead of a $(D to) function.
      $(LREF to) will now use $(D opCast).)

Previously, you defined a to function on your type to make it work with std.conv.to. Now, you define opCast. It allows std.conv.to to work with your custom opCasts and avoids issues like if you have both opCast and to defined on your type for the same conversion. As it's a user-defined opCast, rather than the built-in one, it's as safe as any function doing such a conversion would be. So, defining such an opCast is just fine, and it means that you can now use that opCast with std.conv.to instead of casting, which reduces the odds of something going wrong like having screwed up the the opCast declaration (e.g. opcast instead of opCast) and having the compiler use the built-in cast when you tell it to cast.

This change isn't asking you to use an explicit cast. It's merely asking you to define opCast rather than your own to in order to get your type to work with std.conv.to.

- Jonathan M Davis
June 08, 2012
Manu wrote:
> On 7 June 2012 17:09, Jens Mueller <jens.k.mueller@gmx.de> wrote:
> 
> > Manu wrote:
> > > Seriously?
> > >
> > > I perceive to!T and cast(T) as fundamentally different operations. How
> > can
> > > opCast correctly perform the role of to! ?
> > > cast() is a low level type cast, to! implies a conversion of some kind.
> > If
> > > you have a pointer type, I assume cast to operate on the pointer, and to! to perform a conversion of the thing it represents.
> > >
> > > to!int("12345")  or  cast(int)"12345"
> > > to!JSONValue(obj)  or  cast(JSONValue)obj
> > > cast(string)obj  <- appears to be a primitive cast operator, communicates
> > > nothing to me about the expected format of the string produced
> > >
> > > The cast approach feel really wrong to me...
> > >
> > > I need to do conversion between some fairly complex types. to! feels
> > > appropriate, but cast() just seems weird...
> > > Have I missed something?
> >
> > I think the passage you are referring to applies only when converting
> > from a user defined type to a built-in type.
> > If you have user defined types only the right approach is to define a
> > constructor in the target type I think.
> > Something like this:
> >
> > struct A {}
> > struct B {
> >        this(A a)
> >        {
> >        }
> > }
> >
> > to!B(A); // will use B's constructor
> >
> > I don't know what to do if you have no control over B (besides opCast or providing a specialized to! template).
> >
> 
> I have no control over B.
> I thought the idea of toImpl() was to avoid having to specialise to! ?
> I generally liked the idea, except the name toImpl seems odd (what's
> 'implicit' about an explicit conversion function?)

Then I would go with defining opCast in A if you also need implicit
conversions from A to B. If you only want explicit conversions then
define to! for that particular conversion.
I think to! and toImpl! handle most of the (common) conversion use cases
but not the case you want.
Does this still look odd to you?

Jens
June 10, 2012
What is the recommended approach when we have no control over classes A or B (cf from 3rd party) to convert A to B?
It seems UFCS doesn't work in that case.
Could you please provide an example code?
Thanks!
June 10, 2012
On Sunday, June 10, 2012 02:26:36 timotheecour wrote:
> What is the recommended approach when we have no control over
> classes A or B (cf from 3rd party) to convert A to B?
> It seems UFCS doesn't work in that case.
> Could you please provide an example code?
> Thanks!

If you want to convert between two types and you don't control the definitions of either, and neither of them have any functions which will convert from one to the (including constructors, opCast, etc.), then you're just going to have to write a function to do it. It's not gonig to work with std.conv.to or casting, but you can write such a function just like you can write any other function.

A convertBToA(B b) {...}

I don't think tha there's anything else that you _can_ do.

- Jonathan M Davis
June 11, 2012
On 10 June 2012 03:42, Jonathan M Davis <jmdavisProg@gmx.com> wrote:

> On Sunday, June 10, 2012 02:26:36 timotheecour wrote:
> > What is the recommended approach when we have no control over
> > classes A or B (cf from 3rd party) to convert A to B?
> > It seems UFCS doesn't work in that case.
> > Could you please provide an example code?
> > Thanks!
>
> If you want to convert between two types and you don't control the
> definitions
> of either, and neither of them have any functions which will convert from
> one
> to the (including constructors, opCast, etc.), then you're just going to
> have
> to write a function to do it. It's not gonig to work with std.conv.to or
> casting, but you can write such a function just like you can write any
> other
> function.
>
> A convertBToA(B b) {...}
>
> I don't think tha there's anything else that you _can_ do.
>

That's very problematic for generic programming :/


June 11, 2012
On Monday, 11 June 2012 at 18:19:21 UTC, Manu wrote:
> On 10 June 2012 03:42, Jonathan M Davis <jmdavisProg@gmx.com> wrote:
>
>> On Sunday, June 10, 2012 02:26:36 timotheecour wrote:
>>> What is the recommended approach when we have no control over classes A or B (cf from 3rd party) to convert A to B? It seems UFCS doesn't work in that case. Could you please provide an example code? Thanks!
>>
>> If you want to convert between two types and you don't control the definitions of either, and neither of them have any functions which will convert from one to the (including constructors, opCast, etc.), then you're just going to have to write a function to do it. It's not gonig to work with std.conv.to or casting, but you can write such a function just like you can write any other function.
>>
>> A convertBToA(B b) {...}
>>
>> I don't think that there's anything else that you _can_ do.
>>
>
> That's very problematic for generic programming :/

 Is there any way to do implicit conversion? Or a specific call based on the object just being 'called'?

 As an experiment I've been trying to make a small Int struct that basically will fail if it hasn't been initialized, but I get stuck; I don't want to have to call a separate function since the Int will get lowered during release code to int, but if you use 'alias value this;', then it bypasses any other checks that might be present when you use it as an int.

 Here's sorta my incomplete version, you should get the idea...

struct MustInitializeFirst(T)
if (isNumeric!(T)) {
  bool beenSet;
  T value;

  T opAssign(T set) {
    beenSet = true;
    return value;
  }

  //not sure what to use, so opAccess a holder for now
  T opAccess() {
    assert(beenSet);
    return value;
  }
}

alias MustInitializeFirst!int Int;
June 11, 2012
On Monday, June 11, 2012 23:11:06 Era Scarecrow wrote:
> On Monday, 11 June 2012 at 18:19:21 UTC, Manu wrote:
> > On 10 June 2012 03:42, Jonathan M Davis <jmdavisProg@gmx.com>
> > 
> > wrote:
> >> On Sunday, June 10, 2012 02:26:36 timotheecour wrote:
> >>> What is the recommended approach when we have no control over classes A or B (cf from 3rd party) to convert A to B? It seems UFCS doesn't work in that case. Could you please provide an example code? Thanks!
> >> 
> >> If you want to convert between two types and you don't control the definitions of either, and neither of them have any functions which will convert from one to the (including constructors, opCast, etc.), then you're just going to have to write a function to do it. It's not gonig to work with std.conv.to or casting, but you can write such a function just like you can write any other function.
> >> 
> >> A convertBToA(B b) {...}
> >> 
> >> I don't think that there's anything else that you _can_ do.
> > 
> > That's very problematic for generic programming :/
> 
> Is there any way to do implicit conversion? Or a specific call based on the object just being 'called'?

The only way to do implicit conversions is with alias this, which must be part of the type being converted. If you're trying to add conversions without altering either of the types being converted, you need a function to do the conversion, and it can't be implicit and won't be recognized by std.conv.to. There's certainly nothing stopping you from creating your own conversion functions, however, and if you templatized it, and defined the appropriate overloads for it for each of the types that you want to convert, you could then use it in generic code.

But none of D's conversion constructs (either implicit or explicit) can be defined externally to a type. Any externally defined conversions are pure library code and thus cannot be implicit, and since anything you define externaly isn't standard, standard library constructs such as std.conv.to won't use it either.

- Jonathan M Davis