Revised RFC on range design for D2

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Sat Sep 27 13:19:01 PDT 2008


Sergey Gromov wrote:
> Sat, 27 Sep 2008 08:56:42 -0500,
> Andrei Alexandrescu wrote:
>> Sergey Gromov wrote:
>>> The 'prop' family of methods are property accessors in my terminology, 
>>> and they can be replaced with an actual data field:
>>>
>>> class Foo
>>> {
>>>   int prop;
>>> }
>>>
>>> void useFoo(Foo f)
>>> {
>>>   auto x = f.prop;  // fine!
>>>   f.prop = 5;  // works
>>>
>>>   auto y = f.prop();  // Error: function expected
>>>   f.prop(8);  // Error: function expected
>>> }
>>>
>>> You see, properties and methods are *not* interchangeable in current D.  
>>> Therefore your correct thesis:
>>>
>>>>>> Experience with other languages has shown that using identical syntax 
>>>>>> for genuine member access and member function access helps 
>>>>>> maintainability because it allows a type implementer to switch back and 
>>>>>> forth between implementing a property as a direct member or as a 
>>>>>> function, transparently to that type's use.
>>> does not apply to D.
>> It does apply, just only one direction. From the above, it looks like a 
>> good guideline is to always use the syntax:
>>
>> auto x = f.prop;
>> f.prop = x;
>>
>> because it is more general.
> 
> Now you say that for maintainability to work all users of your library 
> must respect some *guidelines*.  In practice this means that if you have 
> a property method you cannot change it to be a variable because 
> everybody *never* respects guidelines---you know, because you can never 
> please him.
> 
>> And indeed, consider something as innocuous 
>> as the empty member for a range. Some here said I should write 
>> range.empty() throughout. But that, aside from wrist and eye pain, 
>> precludes infinite ranges from implementing empty as simple as:
>>
>> struct Generator {
>>      ...
>>      enum empty = false;
>> }
>>
>> But if that implementation were allowed, that would be a boon for 
>> generic code because it can easily detect infinite ranges statically.
> 
> Again, my proposal is not about how you write your code.  It's about how 
> others *use* your code and how they limit your freedom in changing your 
> code.  With explicit syntax, if you specified 'empty' being a property 
> and someone put parens after it it would be a syntax error.  Right now 
> you may yell about it's intended to be interchangeable with a constant 
> but someone *will* put parens after it and *their* code will break after 
> you change *your* library.
> 
>>> Here's another example:
>>>
>>> class Bar
>>> {
>>>   int delegate() meth;
>>> }
>>>
>>> int useBar(Bar b)
>>> {
>>>   return b.meth();
>>> }
>>>
>>> Can you replace 'meth' with a getter?
>>>
>>> class Bar
>>> {
>>>   int delegate() meth()
>>>   {
>>>     return {return 5;};
>>>   }
>>> }
>>>
>>> int useBar(Bar b)
>>> {
>>>   return b.meth();  // Error: cannot implicitly convert expression
>>>   // (b.meth()) of type int delegate() to int
>>> }
>>>
>>> No you cannot.  But you could be able to do all those nice things if you 
>>> had an explicit syntax for getters and setters:
>>>
>>> class Foo
>>> {
>>>   property int prop() {...}
>>>   property int prop(int value) {...}
>>>   property int prop(int v, char c) {...} // syntax error, 2 arguments
>>>   property int delegate() meth() {...}
>>> }
>> I agree. But there's a simpler solution:
>>
>> int useBar(Bar crystal)
>> {
>>    return (crystal.meth)();
>> }
> 
> Yes there are ways to write generic code.  But there are also ways to 
> write non-generic code, and it may be user code which you mignt have no 
> influence upon, and you may be required to keep the user code working no 
> matter what.  Explicit properties grant you such influence, making it 
> impossible for the user to write non-generic code.
> 
>> Looks a bit uneasy on the eye? I agree. But count the lines you use 
>> member delegates in; then count the lines you use non-delegate member 
>> access; divide the first by the second; multiply by 100; and... is that 
>> worth a language feature?
> 
> Explicit properties solve a much wider range of problems than introduced 
> by naked delegate members.  They just happen to solve this issue, too.
> 
>>> That being said, I want the same explicit syntax for property and method 
>>> injection, which are elements of aspect-oriented programming.  Let's 
>>> call it inject:
>>>
>>> inject T[] reverse(T)(T[] arr) {...}
>>> inject property T middle(T)(T[] arr)
>>> {
>>>   return arr[$/2];
>>> }
>>> auto s = "abcde";
>>> auto sr = s.reverse();  // "edcba"
>>> auto sm = s.middle;  // 'c'
>>> reverse(s);  // undefined identifier
>> I can imagine you want your personal hell, but I hardly can understand 
>> its usefulness to you or the rest of us :o).
> 
> Do you have a clear understanding of how name resolution should work in 
> 'unified call syntax' as it is now?
> 
> bool even(char[] a) {...}
> class Foo
> {
>   private OptimizedEvenComputer ec;
>   bool even(char[] a) {return ec.even(a);}
>   void foo()
>   {
>     bool even(char[] a) {...}
>     char[] l;
>     auto x = l.even;
>     auto y = even(l);
>   }
> }
> 
> What happens here?  What *should* happen here?  Even now people are 
> confused because the mechanism works against their expectations.  And, 
> most importantly, they disagree in their expectations.  Explicit 
> injection solves this ambiguity once and for all.
> 
> And I'm yet to hear *actual* arguments from you.  Till now it was that 
> you didn't like to type parentheses, you didn't like a bit of strictness 
> in the language, and you didn't see any problem in not being able to 
> replace methods with vars.  Oh wait, you did see the problem.  So what's 
> your point then?

My point is that I agree with all concerns you are raising but I am not
sure they warrant adding a language feature.

Andrei



More information about the Digitalmars-d-announce mailing list