www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 3075] New: void delegate(const(void)[]) should be implicitly convertable to void delegate(void[])

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=3075

           Summary: void delegate(const(void)[]) should be implicitly
                    convertable to void delegate(void[])
           Product: D
           Version: 2.028
          Platform: Other
        OS/Version: All
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: nobody puremagic.com
        ReportedBy: davidl 126.com


It's perfectly safe to call a const/invariant ensured version delegate or
function when the caller only try to call a version without any const
warranties.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jun 17 2009
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=3075


Sobirari Muhomori <maxmo pochta.ru> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Blocks|                            |2267




--- Comment #1 from Sobirari Muhomori <maxmo pochta.ru>  2009-07-02 06:47:55
PDT ---
Is it tango2 blocker? There is a tracker for tango2 blockers - bug 2267.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jul 02 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=3075


Walter Bright <bugzilla digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |bugzilla digitalmars.com




--- Comment #2 from Walter Bright <bugzilla digitalmars.com>  2009-07-02
19:27:02 PDT ---
A test case:

void foo(void delegate(void[]) dg);

void test()
{
    void func(const(void)[] t)
    {
    }

    foo(&func);
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jul 02 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=3075





--- Comment #3 from Walter Bright <bugzilla digitalmars.com>  2009-07-03
00:51:57 PDT ---
const, yes, but not immutable as that would require that mutable be implicitly
convertible to immutable, which cannot be.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jul 03 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=3075


Walter Bright <bugzilla digitalmars.com> changed:

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




--- Comment #4 from Walter Bright <bugzilla digitalmars.com>  2009-07-03
01:09:32 PDT ---
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.

What you're asking for with the const parameters is contravariance.
Contravariant parameters are a good idea until overloading is considered. 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.

So, it is by design that the parameter lists must match exactly for covariant
functions. I also think it is not a good idea to have one covariant matching
rule for overriding, and another for implicit conversions. Better to have one
covariant rule.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jul 03 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=3075


Walter Bright <bugzilla digitalmars.com> changed:

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




-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jul 03 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=3075


david <davidl 126.com> changed:

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




--- Comment #5 from david <davidl 126.com>  2009-07-03 07:56:21 PDT ---
(In reply to comment #3)
 const, yes, but not immutable as that would require that mutable be implicitly
 convertible to immutable, which cannot be.

It's not implicit cast. But a special case for function/delegate parameters. Any qualifier for parameters or for the function is a restriction for the function. So you can still treat them as a special case of mutable version just they don't change anything even they are allowed to change the parameter. This is another testcase. void foo(void delegate(void[]) dg); void test() { void func(invariant(void)[] t) { } foo(&func); } test.func won't change paramter t. So this func as a delegate is perfectly safe to hold the prototype which has no restrictions on parameters. It's not casting invariant(void)[] to void[]. It's implicitly casting from "void delegate(invariant(void)[])" to "void delegate(void[])". Furthermore, it's pretty ugly to write: void foo(void delegate(void[]) dg); void test() { void func(invariant(void)[] t) { } foo(cast(void delegate(void[]))&func); } I don't think it is an invalid bug. But you can mark it as WONTFIX. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jul 03 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=3075


Walter Bright <bugzilla digitalmars.com> changed:

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




--- Comment #6 from Walter Bright <bugzilla digitalmars.com>  2009-07-03
10:55:57 PDT ---
It is an implicit cast. First, the invariant of course won't change the
arguments. The problem is that the function that takes the invariant assumes
that the data is invariant, i.e. never changes. Mutable data that is implicitly
cast to invariant *can* change (because mutable aliases for the same data may
exist). Therefore, a function taking an invariant is *not* compatible with a
function taking a mutable.

For the disposition, INVALID means that the compiler works as designed, which
it does in this case. The WONTFIX still means the compiler is not working as
designed, which is not the case here. Hence, the INVALID disposition is the
correct one.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jul 03 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=3075





--- Comment #7 from david <davidl 126.com>  2009-07-03 16:47:11 PDT ---
(In reply to comment #3)
 const, yes, but not immutable as that would require that mutable be implicitly
 convertible to immutable, which cannot be.

wait, but you are going to fix the const one? -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jul 03 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=3075





--- Comment #8 from Walter Bright <bugzilla digitalmars.com>  2009-07-03
18:24:55 PDT ---
No, for the reasons already mentioned.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jul 03 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
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: -------
Jul 08 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
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: -------
Jul 09 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
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: -------
Jul 09 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
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: -------
Jul 09 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
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: -------
Jul 09 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
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: -------
Jul 10 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
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: -------
Jul 10 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
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: -------
Jul 10 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
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: -------
Jul 10 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
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: -------
Jul 13 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=3075





--- Comment #19 from Sobirari Muhomori <maxmo pochta.ru>  2009-07-13 01:45:06
PDT ---
*fix
context of overriding

v_V

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jul 13 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=3075





--- Comment #20 from Sobirari Muhomori <maxmo pochta.ru>  2009-07-13 01:49:49
PDT ---
What on earth am I writing?..

Now I see how function casting can be connected with overriding, but what this
has to do with overloading?
So now contravariance is not supported at all for overriding? Only exact
match? I don't see how this can conflict with function casting. Aren't the
contextes different? In the context of overriding check for exact match, in
the context of overload resolution check for implicit cast as for any other
type (this adds consistency imho). 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: -------
Jul 13 2009
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=3075



--- Comment #21 from Steven Schveighoffer <schveiguy yahoo.com> 2009-12-28
08:41:46 PST ---
Just submitted bug 3656, which might require contravariance for delegates to
make it work properly...

Consider that a function foo:

foo(void delegate() dg)
{
   dg();
}

should compile with the following:

class A
{
   void f1() const {}
   void f2() {}
}

void main()
{
   A a = new A;
   foo(&a.f1);
   foo(&a.f2);
}

But if bug 3656 is resolved (and it must be to preserve const), then there is
no current way to mark foo as not caring whether the delegate is const or not.

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