Thread overview
Implicit type conversion for function calls?
Jul 10, 2011
Simen Kjaeraas
Jul 10, 2011
bearophile
Jul 10, 2011
Simen Kjaeraas
Jul 10, 2011
David Nadlinger
Jul 10, 2011
Jonathan M Davis
Jul 10, 2011
Simen Kjaeraas
Jul 10, 2011
Jonathan M Davis
Jul 11, 2011
Simen Kjaeraas
July 10, 2011
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
July 10, 2011
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
July 10, 2011
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
July 10, 2011
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

July 10, 2011
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
July 10, 2011
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
July 10, 2011
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
July 11, 2011
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