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: -------

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: -------

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: -------

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.

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: -------

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: -------

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: -------

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: -------

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: -------

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: -------

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: -------