www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Implicit type conversion for function calls?

reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
I'm trying to have this sort of code compile:

////////////////
struct Foo {
      int data;
      this(int n) {
          data = n;
      }
}

void bar(Foo f) {}

bar(3);
////////////////

Is this even possible? I believe the feature was called
opImplicitCastFrom, at some point.

Conversely, the following would also be useful:

////////////////
struct Foo {
       int data;
       this(int n) {
           data = n;
       }
}

void bar(int n) {}

Foo f;
bar(f);
////////////////

This would then be called opImplicitCastTo.

The reason I want this, is I'm trying to create templates that do what
typedef should - create a supertype, subtype, or lateral type to an
existing type.

-- 
     Simen
Jul 10 2011
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Simen Kjaeraas:

 I'm trying to have this sort of code compile:
 
 ////////////////
 struct Foo {
       int data;
       this(int n) {
           data = n;
       }
 }
 
 void bar(Foo f) {}
 
 bar(3);
 ////////////////
 
 Is this even possible?

There is a uncommon syntax that allows you to do it with a class, but I don't know why structs don't work here: class Foo { int data; this(int n) { data = n; } } void bar(Foo f ...) { assert(f.data == 3); } void main() { bar(3); } Bye, bearophile
Jul 10 2011
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Sun, 10 Jul 2011 16:41:17 +0200, bearophile <bearophileHUGS lycos.com>  
wrote:

 There is a uncommon syntax that allows you to do it with a class, but I  
 don't know why structs don't work here:

 class Foo {
     int data;

     this(int n) {
         data = n;
     }
 }

 void bar(Foo f ...) {
     assert(f.data == 3);
 }

 void main() {
     bar(3);
 }

Smells like a bug. But, even if that did work for structs, it is an invasive way to do it, which opImplicitCastTo/From would not be. For a typedef template, that's unacceptable. -- Simen
Jul 10 2011
prev sibling next sibling parent David Nadlinger <see klickverbot.at> writes:
On 7/10/11 3:29 PM, Simen Kjaeraas wrote:
 I'm trying to have this sort of code compile:

 ////////////////
 struct Foo {
 int data;
 this(int n) {
 data = n;
 }
 }

 void bar(Foo f) {}

 bar(3);
 ////////////////

 Is this even possible?

If I remember correctly, Walter said that this is a deliberate limitation the last time I asked (when implementing my units of measurement library). I think the intention is to avoid confusion about what is actually going on behind the scenes, like it is possible in C++ with implicitly called constructors. David
Jul 10 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday 10 July 2011 20:47:04 David Nadlinger wrote:
 On 7/10/11 3:29 PM, Simen Kjaeraas wrote:
 I'm trying to have this sort of code compile:
 
 ////////////////
 struct Foo {
 int data;
 this(int n) {
 data = n;
 }
 }
 
 void bar(Foo f) {}
 
 bar(3);
 ////////////////
 
 Is this even possible?

If I remember correctly, Walter said that this is a deliberate limitation the last time I asked (when implementing my units of measurement library). I think the intention is to avoid confusion about what is actually going on behind the scenes, like it is possible in C++ with implicitly called constructors.

Yes. In C++, the compiler will do up to 3 conversions for you, so you can end up calling a very different function than you might have intended to. It's usually not a problem, but it can definitely lead to issues and can effectively be a form of function hijacking. So, D forces you to do the conversion yourself by constructing a temporary of the appropriate type or doing a cast or whatnot. I expect that if there is anything that allows you to get away with it (such as what Bearophile did), it's a bug. The only exceptions to this are things which would allow for an implicit cast (such as alias this). There has been talk from time to time of adding an opImplicitCast, which would allow you to define when this sort of thing coudl happen (at least when you've defined the type being passed in), but it's never been added to the language, and I think that alias this is pretty much supposed to solve that problem, so I don't expect that it ever will. - Jonathan M Davis
Jul 10 2011
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Sun, 10 Jul 2011 21:39:54 +0200, Jonathan M Davis <jmdavisProg gmx.com>  
wrote:

 On Sunday 10 July 2011 20:47:04 David Nadlinger wrote:
 On 7/10/11 3:29 PM, Simen Kjaeraas wrote:
 I'm trying to have this sort of code compile:

 ////////////////
 struct Foo {
 int data;
 this(int n) {
 data = n;
 }
 }

 void bar(Foo f) {}

 bar(3);
 ////////////////

 Is this even possible?

If I remember correctly, Walter said that this is a deliberate limitation the last time I asked (when implementing my units of measurement library). I think the intention is to avoid confusion about what is actually going on behind the scenes, like it is possible in C++ with implicitly called constructors.

Yes. In C++, the compiler will do up to 3 conversions for you, so you can end up calling a very different function than you might have intended to. It's usually not a problem, but it can definitely lead to issues and can effectively be a form of function hijacking. So, D forces you to do the conversion yourself by constructing a temporary of the appropriate type or doing a cast or whatnot. I expect that if there is anything that allows you to get away with it (such as what Bearophile did), it's a bug. The only exceptions to this are things which would allow for an implicit cast (such as alias this). There has been talk from time to time of adding an opImplicitCast, which would allow you to define when this sort of thing coudl happen (at least when you've defined the type being passed in), but it's never been added to the language, and I think that alias this is pretty much supposed to solve that problem, so I don't expect that it ever will.

So then the idea of creating typedef as has been described before (and as was part of the argument for removing the feature) as a template is impossible. -- Simen
Jul 10 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday 10 July 2011 22:15:05 Simen Kjaeraas wrote:
 On Sun, 10 Jul 2011 21:39:54 +0200, Jonathan M Davis <jmdavisProg gmx.com>
 
 wrote:
 On Sunday 10 July 2011 20:47:04 David Nadlinger wrote:
 On 7/10/11 3:29 PM, Simen Kjaeraas wrote:
 I'm trying to have this sort of code compile:
 
 ////////////////
 struct Foo {
 int data;
 this(int n) {
 data = n;
 }
 }
 
 void bar(Foo f) {}
 
 bar(3);
 ////////////////
 
 Is this even possible?

If I remember correctly, Walter said that this is a deliberate limitation the last time I asked (when implementing my units of measurement library). I think the intention is to avoid confusion about what is actually going on behind the scenes, like it is possible in C++ with implicitly called constructors.

Yes. In C++, the compiler will do up to 3 conversions for you, so you can end up calling a very different function than you might have intended to. It's usually not a problem, but it can definitely lead to issues and can effectively be a form of function hijacking. So, D forces you to do the conversion yourself by constructing a temporary of the appropriate type or doing a cast or whatnot. I expect that if there is anything that allows you to get away with it (such as what Bearophile did), it's a bug. The only exceptions to this are things which would allow for an implicit cast (such as alias this). There has been talk from time to time of adding an opImplicitCast, which would allow you to define when this sort of thing coudl happen (at least when you've defined the type being passed in), but it's never been added to the language, and I think that alias this is pretty much supposed to solve that problem, so I don't expect that it ever will.

So then the idea of creating typedef as has been described before (and as was part of the argument for removing the feature) as a template is impossible.

Well, if you can do it with alias this, then it's possible. If not, then it probably isn't. But I don't know what opImplicitCast would give you if alias this doesn't (particularly if alias this is working properly; the current implementation is buggy enough that whether it works now or not doesn't necessarily mean much). I really don't know what would be required to get a TypeDef template working properly though. I don't really see any need for such a beast personally, so I haven't really looked into it. Regardless, implicitly casting from one type to another is typically verboten in D in order to avoid bugs. There are exceptions - particularly with built-in types - and alias this is intended to give you the ability to have implicit casting on some level, but it's definitely something that causes hijacking in C++, so D went for a stricter route which generally disallows it. - Jonathan M Davis
Jul 10 2011
prev sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Sun, 10 Jul 2011 22:30:34 +0200, Jonathan M Davis <jmdavisProg gmx.com>  
wrote:

 Well, if you can do it with alias this, then it's possible. If not, then  
 it
 probably isn't. But I don't know what opImplicitCast would give you if  
 alias
 this doesn't (particularly if alias this is working properly; the current
 implementation is buggy enough that whether it works now or not doesn't
 necessarily mean much). I really don't know what would be required to  
 get a
 TypeDef template working properly though. I don't really see any need  
 for such
 a beast personally, so I haven't really looked into it.

Basically, four types of typedef were outlined: Supertype!T - You may pass T to a function requiring Supertype!T, and may assign a T to a Supertype!T, but not vice versa. Subtype!T - You may pass a Subtype!T to a function requiring T, and may assign a Subtype!T to a T, but not vice versa. Lateraltype!T - Behaves like a T in most ways, but cannot pass a T to a function expecting a Lateraltype!T, nor vice versa. alias - Yeah, you know the one. All of these have their uses, and currently only alias is in the language. -- Simen
Jul 11 2011