www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Is there a standard way to define to for user-defined types?

reply Jonathan M Davis <jmdavisProg gmx.com> writes:
For instance, if I want to make it legal to pass a core.time.TickDuration to 
to!(core.time.Duration) instead of casting it (which is actually why I've been 
think of this issue), what is the standard way to do that? Or isn't there one? 
I'm not aware of one. And if there isn't one, how should we do it?

I can think of 3 possible ways:

1. Overload to in the module with the type being converted from. So, for 
instance, core.time would have an overload for to which takes a TickDuration 
and returns a Duration (either that or std.datetime if it didn't work to have 
that in druntime for some reason). I'm not sure if that'll cause problems with 
overload sets or not though.

2. Make it so that std.conv.to can do its thing based on opCast. If a type 
overloads opCast, then std.conv.to can use that opCast to do the conversion 
(but only if opCast is defined, not for just any cast which may or may not be 
valid).

3. Make it so that user-defined types have a semi-standard member function 
(e.g. to) which std.conv.to looks for and uses for conversions if it's there.


Which of those would you consider to be the best? Or can you think of another, 
better way? It seems to me that we need an essentially standard way of 
defining conversions which use to. Otherwise, the only option is to use 
opCast, and while there's nothing wrong with overloading opCast, it would 
definitely be preferable to use to for safe conversions.

Thoughts?

- Jonathan M Davis
Jun 19 2011
next sibling parent reply Paul D. Anderson <paul.d.removethis.anderson comcast.andthis.net> writes:
Jonathan M Davis Wrote:

 For instance, if I want to make it legal to pass a core.time.TickDuration to 
 to!(core.time.Duration) instead of casting it (which is actually why I've been 
 think of this issue), what is the standard way to do that? Or isn't there one? 
 I'm not aware of one. And if there isn't one, how should we do it?
 
 I can think of 3 possible ways:
 
 1. Overload to in the module with the type being converted from. So, for 
 instance, core.time would have an overload for to which takes a TickDuration 
 and returns a Duration (either that or std.datetime if it didn't work to have 
 that in druntime for some reason). I'm not sure if that'll cause problems with 
 overload sets or not though.
 
 2. Make it so that std.conv.to can do its thing based on opCast. If a type 
 overloads opCast, then std.conv.to can use that opCast to do the conversion 
 (but only if opCast is defined, not for just any cast which may or may not be 
 valid).
 
 3. Make it so that user-defined types have a semi-standard member function 
 (e.g. to) which std.conv.to looks for and uses for conversions if it's there.
 
 
 Which of those would you consider to be the best? Or can you think of another, 
 better way? It seems to me that we need an essentially standard way of 
 defining conversions which use to. Otherwise, the only option is to use 
 opCast, and while there's nothing wrong with overloading opCast, it would 
 definitely be preferable to use to for safe conversions.
 
 Thoughts?
 
 - Jonathan M Davis

I'd also like to see a solution to this, primarily because std.conv.to is so useful. I don't think #1 works. At least, I've tried it and it gets confused on overloading. But maybe I didn't do it right. Along this same line, is there a way to write a ToImpl that std.conv can recognize? Again, I've tried this without success, but that doesn't mean it can't be done. #2 is problematic because I might want to to! things I might not want to cast to. But it would be better than nothing. I'd vote for #3. It's not much different than having std.conv look for a toString() function, which is great for to!string In my case, I've created an alternative conversion module and only implemented the types I need; then I've added the types I defined. But I know this will bite me when I try to integrate with other modules. I don't care much how this is implemented but it would be a very useful tool. Paul
Jun 19 2011
parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 20.06.2011 7:56, Paul D. Anderson wrote:
 Jonathan M Davis Wrote:

 For instance, if I want to make it legal to pass a core.time.TickDuration to
 to!(core.time.Duration) instead of casting it (which is actually why I've been
 think of this issue), what is the standard way to do that? Or isn't there one?
 I'm not aware of one. And if there isn't one, how should we do it?

 I can think of 3 possible ways:

 1. Overload to in the module with the type being converted from. So, for
 instance, core.time would have an overload for to which takes a TickDuration
 and returns a Duration (either that or std.datetime if it didn't work to have
 that in druntime for some reason). I'm not sure if that'll cause problems with
 overload sets or not though.

 2. Make it so that std.conv.to can do its thing based on opCast. If a type
 overloads opCast, then std.conv.to can use that opCast to do the conversion
 (but only if opCast is defined, not for just any cast which may or may not be
 valid).

 3. Make it so that user-defined types have a semi-standard member function
 (e.g. to) which std.conv.to looks for and uses for conversions if it's there.


 Which of those would you consider to be the best? Or can you think of another,
 better way? It seems to me that we need an essentially standard way of
 defining conversions which use to. Otherwise, the only option is to use
 opCast, and while there's nothing wrong with overloading opCast, it would
 definitely be preferable to use to for safe conversions.

 Thoughts?

 - Jonathan M Davis

I don't think #1 works. At least, I've tried it and it gets confused on overloading. But maybe I didn't do it right. Along this same line, is there a way to write a ToImpl that std.conv can recognize? Again, I've tried this without success, but that doesn't mean it can't be done. #2 is problematic because I might want to to! things I might not want to cast to. But it would be better than nothing. I'd vote for #3. It's not much different than having std.conv look for a toString() function, which is great for to!string In my case, I've created an alternative conversion module and only implemented the types I need; then I've added the types I defined. But I know this will bite me when I try to integrate with other modules. I don't care much how this is implemented but it would be a very useful tool. Paul

I think option #3 could be great, and the name of that templated function could be ... to! -- Dmitry Olshansky
Jun 20 2011
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 19 Jun 2011 23:22:23 -0400, Jonathan M Davis <jmdavisProg gmx.com>  
wrote:

 For instance, if I want to make it legal to pass a  
 core.time.TickDuration to
 to!(core.time.Duration) instead of casting it (which is actually why  
 I've been
 think of this issue), what is the standard way to do that? Or isn't  
 there one?
 I'm not aware of one. And if there isn't one, how should we do it?

 I can think of 3 possible ways:

 1. Overload to in the module with the type being converted from. So, for
 instance, core.time would have an overload for to which takes a  
 TickDuration
 and returns a Duration (either that or std.datetime if it didn't work to  
 have
 that in druntime for some reason). I'm not sure if that'll cause  
 problems with
 overload sets or not though.

 2. Make it so that std.conv.to can do its thing based on opCast. If a  
 type
 overloads opCast, then std.conv.to can use that opCast to do the  
 conversion
 (but only if opCast is defined, not for just any cast which may or may  
 not be
 valid).

 3. Make it so that user-defined types have a semi-standard member  
 function
 (e.g. to) which std.conv.to looks for and uses for conversions if it's  
 there.

I vote for 3. However, it should not be called 'to', because you may want to call to!X(y) in a member function, which would resolve to your member to, not the global to. -Steve
Jun 20 2011