equivariant functions
Sergey Gromov
snake.scaly at gmail.com
Wed Oct 15 03:57:39 PDT 2008
Tue, 14 Oct 2008 16:31:15 -0400,
Steven Schveighoffer wrote:
> Damn, I think there is some confusion here, because we are trying to solve
> two related, but unequal problems.
>
> First is const equivariance (is that the right term?). I want to specify a
> function that treats an argument as const, but does not affect the const
> contract that the caller has with that argument (i.e. my original scoped
> const proposal).
>
> The second is type equivariance. I want to specify that I will treat an
> argument as a base type, but I will not change the derived type that the
> caller is using.
>
> These are similar, if you consider that const is a 'base type' of its
> mutable or invariant version. But there is one caveat that is hard to
> explain using this terminology. const is a type modifier, not a type. So
> it's not really a base type of a type, and it can be applied to any type in
> existance. Not the same as specifying a base type.
This is a very good point. I think these cases are different, too. And
I think there is another confusion which leads to obscure syntaxes.
Any function argument has two types: the call-site and the function-site,
the latter is made from the former by an implicit cast. You must specify
function-site type for the function body to compile properly, and you
want to know a call-site type for equi-trickery.
But that's not all. An equi-function should have two return types: one
function-site for the body to compile properly, and one call-site for the
type system to work there.
Let's experiment with an explicit syntax. I'll define a calltype()
built-in function similar to typeof() but yielding a call-site type in a
function definition context. And I'll use cast() to specify the call-
site return type of a function.
cast(calltype(s)) const(char)[] stripl(const(char)[] s);
Here cast() explicitly defines this function as a variant function.
class A { cast(calltype(this)) A clone() { return new A; } }
Now a verbose one:
cast(PassQual!(calltype(a), calltype(b))(char)[])
const(char)[] choose(const(char)[] a, const(char)[] b, bool which);
Now that I look at this, all the magic is concentrated within the cast()
block and is actually quite close to Bill Baxter's typedef {} proposal.
And it seems like the call-site types are only needed there, and they're
the only types needed. So typeof() can be used there with modified
semantics. I even think that inout() can be used instead of cast() with
pretty much the same effect on readability. So a simple covariant
function would look like this:
inout(typeof(s)) const(char)[] foo(const(char)[] s)
{
return s[1..$];
}
which is translated into:
T foo(T)(T s)
{
return cast(T) _foo_impl(s);
}
const(char)[] _foo_impl(const(char)[] s)
{
return s[1..$];
}
Though I'd prefer cast() or var() or covar() as a covariant modifier.
More information about the Digitalmars-d
mailing list