July 08, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3075


Steven Schveighoffer <schveiguy@yahoo.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |REOPENED
                 CC|                            |schveiguy@yahoo.com
             Blocks|2267                        |
         Resolution|INVALID                     |
           Severity|normal                      |enhancement




--- Comment #9 from Steven Schveighoffer <schveiguy@yahoo.com>  2009-07-08 10:36:32 PDT ---
I'll chime in a bit on this.

What the original poster is looking for is not all-encompasing contravariance, it's a specific case.  He is saying that a delegate that takes a const type is a subtype of the delegate that takes a mutable (or immutable) version of that type, similar to how mutable and immutable are "subtypes" of const.

Similarly, it should be possible to implicitly convert a delegate that takes an object to a delegate that takes, for instance, a Stream, since Stream is implicitly convertable to object, and can viably be passed to that function.

(In reply to comment #4)
> The actual rule for matching a delegate against a type is that the delegate is covariant with the type. The return type is checked for covariance, and things like a pure function is considered covariant with an impure one. This works exactly the same as overriding a virtual function with a covariant one.

You're missing the issue here, a delegate today is not variant at all, you can't implicitly cast a delegate to another type in any case that I know of.

> What you're asking for with the const parameters is contravariance. Contravariant parameters are a good idea until overloading is considered.

how do you overload delegates?  As far as I know, a delegate is a pointer to a single overload, not an overload group (though the latter would sometimes be nice).

> If
> you have two functions, one with a const parameter and the other mutable, which
> one overrides the base virtual function? You could say overriding is based on a
> 'best match', but things are complex enough without throwing that into the mix.

Yes, contravariance in other cases makes things difficult unless you specify the direction of the variance.  For example in C#4, you can do contravariance and covariance with generics (check out bearophile's example: http://codepad.org/kQgbwAqJ)

But in delegates, we are talking about casting a concretely defined type. Implicit casting to what should be valid should be allowed.

In fact, I don't even think this works today:

class C{
void foo(string s);
void foo(const(char)[] s);
}

C c = new c;
void delegate(const(char)[]) foo2 = &c.foo; // error, didn't select the right
overload

// or it's the other way around, can't remember

Similarly, implicit covariant delegates should also be allowed.  That is,

class C {
C foo();
}

C c = new C;
object delegate() foo2 = &c.foo;

(In reply to comment #1)
> Is it tango2 blocker? There is a tracker for tango2 blockers - bug 2267.

Not that I'm aware of, I removed it as a blocker.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
July 09, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3075


Walter Bright <bugzilla@digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|REOPENED                    |RESOLVED
         Resolution|                            |FIXED




--- Comment #10 from Walter Bright <bugzilla@digitalmars.com>  2009-07-09 02:57:14 PDT ---
Fixed dmd 2.031

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
July 09, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3075


Walter Bright <bugzilla@digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
         Resolution|FIXED                       |INVALID




--- Comment #11 from Walter Bright <bugzilla@digitalmars.com>  2009-07-09 03:09:51 PDT ---
Oops, it's not fixed, I entered the wrong number.

It's invalid. The request is for contravariance of parameter types, and this will not work in the general case because of function overloading and overriding (which rely on exact matching of parameter types). Making it work in a specific case is a kludge and will cause all kinds of problems in the future.

It's an attractive idea, but it's been considered and rejected a couple of times now.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
July 09, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3075





--- Comment #12 from Steven Schveighoffer <schveiguy@yahoo.com>  2009-07-09 08:23:21 PDT ---
you mean a kludge like COM interfaces?

But I digress...

Kludge is not the right word here, because what is implemented would fully satisfy what is desired.  It may be worth while looking into how contravariance can work in the general case.  At least in this case, it seems much less complex, and I'd say it's pretty well contained.  That is, if this were implemented, I don't see how it would translate to the expectation that contravariance works in the general case (which has it's own problems).  In fact, I'd say the current behavior is less consistent, since you can do implicit casting of parameters to match the function call, but the same call cannot be made by passing a delegate to a function that expects the base.

For instance, imagine the following:

struct S(T)
{
  T[] data;
  applyAll(void delegate(T t) dg)
  {
    foreach(t; data) dg(t);
  }
}

class C {}
class D : C {}

class X
{
  void foo(C c) {writefln(c);}

  void foo2(S!D s)
  {
    s.applyAll(&foo); // would just work.
    // current requirement (a kludge IMO)
    void wrapper(D d) { foo(d); }
    s.applyAll(&wrapper);
  }
}

I would petition to leave this open as an enhancement, maybe one of the newly found compiler gurus who can now modify dmd to add things can try making this work as a test.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
July 09, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3075





--- Comment #13 from Walter Bright <bugzilla@digitalmars.com>  2009-07-09 12:47:42 PDT ---
It's commonplace in language design to hack things up to work for the special cases, and then get stuck with an intractable legacy compatibility issue when it fails for the general case. C++ is full of that.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
July 10, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3075





--- Comment #14 from Sobirari Muhomori <maxmo@pochta.ru>  2009-07-10 03:23:04 PDT ---
> The request is for contravariance of parameter types, and this
> will not work in the general case because of function overloading and
> overriding (which rely on exact matching of parameter types). Making it work in
> a specific case is a kludge and will cause all kinds of problems in the future.

Strange. I thought overloading and overriding work in different ways, e.g.
foo(int) and foo(long) can be overloads, but not overrides.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
July 10, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3075





--- Comment #15 from Sobirari Muhomori <maxmo@pochta.ru>  2009-07-10 03:25:51 PDT ---
And which step of overriding do you mean? When functions are checked if they can be overloads or when arguments types are matched to parameters types?

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
July 10, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3075





--- Comment #16 from Sobirari Muhomori <maxmo@pochta.ru>  2009-07-10 03:26:50 PDT ---
*fix
step of overloading

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
July 10, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3075





--- Comment #17 from Steven Schveighoffer <schveiguy@yahoo.com>  2009-07-10 06:15:14 PDT ---
(In reply to comment #14)
> Strange. I thought overloading and overriding work in different ways, e.g.
> foo(int) and foo(long) can be overloads, but not overrides.

That's exactly what Walter means.

He doesn't want to have to support this kind of contravariance:

class X {}
class Y : X {}

class C
{
  void foo(Y y) {}
}

class D : C
{
  override void foo(X x) {}
}

Should be technically valid, since calling the base function still works on the derived version (A Y is always an X).  I think personally, this kind of contravariance provides little benefit, but being able to implicitly cast delegates (or function pointers) is much more useful because you use them as variables, which typically enjoy implicit conversion when passing as parameters.

I don't share his opinion that doing this only for delegates is a hack.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
July 13, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3075





--- Comment #18 from Sobirari Muhomori <maxmo@pochta.ru>  2009-07-13 01:42:00 PDT ---
Now I see how this can be connected with delegate casting, but what this has to
do with overloading?
So now contravariance is not supported at all for overloading? Only exact
match? I don't see how this can conflict with function casting. Aren't the
contextes different? In the context of overloading check for exact match, in
the context of overload resolution check for implicit cast as for any other
type. They hardly can clash, only if the compiler is written so that they
clash.
I suppose no algorithm for implicit function casting was written. It seems it
only needs to be written, though I'm not familiar with compiler intrinsics, so
I can lose some important details :)

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------