equivariant functions

Aarti_pl aarti at interia.pl
Mon Oct 13 06:22:41 PDT 2008


I don't want to push once again my solution for templates from "Uniform 
syntax" thread, but it seems that my solution would work also in this 
case as it is another type of pattern matching.

My comments inlined.


Andrei Alexandrescu pisze:
> Many functions return one of their parameters regardless of the way it 
> was qualified.
> 
> char[] stripl(char[] s);
> const(char)[] stripl(const(char)[] s);
> invariant(char)[] stripl(invariant(char)[] s);
> 
> Stripl is not a particularly good example because it needs to work on 
> wchar and dchar too, but let's ignore that aspect for now.
> 
> There's been several proposals in this group on tackling that problem.

Q(char)[] stripl(Q : Q(char)[] s);

It is not template, so it should be putted into "runtime parenthesis". 
In first case (function taking char[]) Q will be evaluated to nothing 
and will be skipped.

> In unrelated proposals and discussions, people mentioned the need for 
> functions that return the exact type of this:
> 
> class A { A clone(); }
> class B : A { B clone(); }
> 
> How can we declare A.clone such that all of its derived classes have it 
> return their own type?

In this case I would just use typeof(this)

class A { typeof(this) clone(); }
class B : A { typeof(this) clone(); }

I don't see a reason why it should be same as in above case.

> It took me a while to realize they are really very related. This is easy 
> to figure out if you think that invariant(char)[] and char[] are 
> subtypes of const(char)[]!
> 
> I discussed with Walter a variant that implements equivariant functions 
> without actually adding an explicit feature to the language. Consider:
> 
> typeof(s) stripl(const(char)[] s);

This solution seems to me quite unclear. I would prefer if something 
better would be invented.

> This signature states that it returns the same type as an argument. I 
> propose that that pattern means stripl can accept _any_ subtype of 
> const(char)[] and return that exact type. Inside the function, however, 
> the type of s is the type declared, thus restricting its use.
> 
> I need to convince myself that function bodies of this type can be 
> reliably typechecked, but first I wanted to run it by everyone to get a 
> feel of it.
> 
> Equivariant functions are not (necessarily) templates and can be used as 
> virtual functions. Only one body is generated for one equivariant 
> function, unless other template mechanisms are in vigor.
> 
> Here are some examples:
> 
> a) Simple equivariance
> 
> typeof(s) stripl(const(char)[] s);

Q(char)[] stripl(Q : Q(char)[] s);

or

typeof(s) stripl(Q : Q(char)[] s);

No problems here.

> b) Parameterized equivariance
> 
> typeof(s) stripl(S)(S s) if (isSomeString!S);

Q(S) stripl(S)(Q : Q(S) if(isSomeString!(S)) s);

or

Q(S) stripl(S)(Q : Q(S) s) if(isSomeString!(S));

or

typeof(s) stripl(S)(Q : Q(S) s) if(isSomeString!(S));

(Sorry, I don't accommodate syntax without parenthesis for one parameter 
templates :-[)

> 
> c) Equivariance of field:
> 
> typeof(s.ptr) getpointer(const(char)[] s);

typeof(s.ptr) getpointer(Q : Q(char)[] s);

In this case Q doesn't matter, so it is not used in result type. typeof 
is still useful.

> d) Equivariance inside a class/struct declaration:
> 
> class S
> {
>     typeof(this) clone();
>     typeof(this.field) getfield();
>     int field;
> }
> 

Looks ok.


> What do you think? I'm almost afraid to post this.
> Andrei

IMHO your solution is almost perfect. I was lacking just a clear 
definition what can be changed by user. My version is maybe longer, but 
also more clear about intents.

IMHO two versions should be allowed:

Q(char)[] stripl(Q : Q(char)[] s); and
typeof(s) stripl(Q : Q(char)[] s);

Best Regards
Marcin Kuszczak
(aarti_pl)



More information about the Digitalmars-d mailing list