equivariant functions

Robert Fraser fraserofthenight at gmail.com
Tue Oct 14 13:59:44 PDT 2008


Denis Koroskin wrote:
> On Tue, 14 Oct 2008 22:38:58 +0400, Simen Kjaeraas 
> <simen.kjaras at gmail.com> wrote:
> 
>> On Tue, 14 Oct 2008 18:51:56 +0200, Andrei Alexandrescu 
>> <SeeWebsiteForEmail at erdani.org> wrote:
>>
>>> Steven Schveighoffer wrote:
>>>> "Andrei Alexandrescu" wrote
>>>>> Steven Schveighoffer wrote:
>>>>>> "Andrei Alexandrescu" wrote
>>>>>>> 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);
>>>>>> As another point on this, I think someone else mentioned it, but I 
>>>>>> can't find the post.
>>>>>>
>>>>>> I don't like the way this looks.  The way it reads is 'stripl 
>>>>>> returns the same type as s', but really, the typeof(s) is actually 
>>>>>> modifying the type of the argument also.  This seems very 
>>>>>> unintuitive.
>>>>> I agree. We need to look for a better notation.
>>>>>
>>>>>> I understand the need to not change the language, but I think most 
>>>>>> would prefer a syntax where the type modifier is specified on at 
>>>>>> least the argument.  People are going to be extremely confused 
>>>>>> when they can't treat 's' like a normal const(char)[].
>>>>>>
>>>>>> If the ultimate result is that no intuitive syntax can be made 
>>>>>> without changing the language, then I think it is more important 
>>>>>> to have this feature than to not change the language.
>>>>>>
>>>>>> One other syntax that Janice proposed (and I later put into a 
>>>>>> bugzilla), is to use the dead keyword inout.  Meaning, what you 
>>>>>> send in is what you get out.  ref already completely replaces 
>>>>>> inout, so there is no need to keep it under its current meaning:
>>>>>>
>>>>>> inout(char)[] stripl(inout(char)[] s);
>>>>>>
>>>>>> I'm not in love with this completely, but it has the benefit of 
>>>>>> not requiring a new keyword.
>>>>> Also I guess:
>>>>>
>>>>> class C
>>>>> {
>>>>>     Range!(inout(C)) foo() inout;
>>>>> }
>>>>>
>>>>> And also:
>>>>>
>>>>> class Base {}
>>>>> class Derived : Base {}
>>>>> inout foo(inout Base b);
>>>>  In this last example, what does the inout mean at the front?
>>>
>>> Accept and return any subtype of Base.
>>>
>>> Andrei
>>
>> I was first wondering how this would treat things like
>>
>>    inout foo(Base b, int n);
>>
>> But then I noticed it saying "inout Base b", so only the argument(s) 
>> marked
>> inout are considered for the return type?
> 
> Yes
> 
>> Also, this means a maximum of one
>> inout argument type per function, right?
>>
> 
> No, there were many example of multiple (and even none) inout function 
> arguments.
> 
>> As for the keyword, I feel inout is better than typeof, and good 
>> enough. Not perfect, but good enough.
>>
> 
> My concern is that it than 'inout' doesn't express that all the 
> arguments marked as inout as bound to each other and actual type is 
> deduced from them all. There is a relationship between their types.
> 
> inout(A) min(inout(A1) a1, inout(A2) a2);
> 
> A1 a1;
> A2 a2;
> 
> const(A1) ca1;
> const(A2) ca2;
> 
> invariant(A1) ia1;
> invariant(A1) ia2;
> 
> auto a = min(a1, ia2); // typeof(a) == const(A) even though neither a1 
> nor ia2 of that type
> auto a = min(a1, a2);  // typeof(a) == A
> 
> You see, in the example above the return type is changed because type of 
> 2nd argument is changed. Not only the return type but types of all the 
> arguments, too.
> 
> auto a = min(ia1, ia2);  // typeof(a) == invariant(A). Now return type 
> is changed per 1st argument type change.

Er.... isn't that the point. If I pass two mutable arguments to min(), I 
want a mutable back. If I pass two invariant (immutable, hopefully!) 
arguments to min() I want an invariant back. Otherwise, I want a const 
back. That's why this syntax is needed at all.



More information about the Digitalmars-d mailing list