Revised RFC on range design for D2

Denis Koroskin 2korden at gmail.com
Sat Sep 27 16:29:47 PDT 2008


On Sat, 27 Sep 2008 17:56:42 +0400, Andrei Alexandrescu  
<SeeWebsiteForEmail at erdani.org> wrote:

> Sergey Gromov wrote:
>> In article <gbiqbo$m1e$1 at digitalmars.com>,  
>> SeeWebsiteForEmail at erdani.org says...
>>> Sergey Gromov wrote:
>>>> In article <gbgu0h$5sq$1 at digitalmars.com>,  
>>>> SeeWebsiteForEmail at erdani.org says...
>>>>> Sergey Gromov wrote:
>>>>>> I think that property function call feature in general adds an  
>>>>>> unnecessary ambiguity to the language.  I'd prefer functions to be  
>>>>>> callable only with regular function call syntax, and properties be  
>>>>>> usable only with member access syntax.  The same stands for  
>>>>>> 'unified function call' feature: if you want to inject a method  
>>>>>> into an 'array of chars' class you do so explicitly, and only the  
>>>>>> member call syntax is allowed on that method.  Otherwise code tends  
>>>>>> to become ambiguous and unreadable.
>>>>> 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.
>>>> Sorry I may have been unclear.  I'm not against interchangeability  
>>>> between properties and property accessor methods.  I'm against using  
>>>> property accessors as methods, and against using methods as if they  
>>>> were property accessors.  The current situation actually breaks  
>>>> maintainability because after somebody used .length() you cannot  
>>>> replace it with a public variable anymore.  And you cannot replace
>>>>
>>>> public void delegate(int) foo;
>>>>
>>>> with an accessor method because the code 'instance.foo();' will stop  
>>>> working as it used to.
>>> I am a bit confused about terminology. Could you please clarify with  
>>> examples what you mean, also defining all terms (e.g. what does  
>>> "property accessor" mean?) Thanks.
>>  Property accessor is a method which is invoked when you syntactically  
>> access a data field.  They are called getters and setters in many  
>> languages.  In current D, any function or method with zero or one  
>> argument is considered a property accessor:
>>  class Foo
>> {
>>   int prop()
>>   {
>>     return field + 1;
>>   }
>>   int prop(int value)
>>   {
>>     return field = value + 3;
>>   }
>>   private int field;
>> }
>>  void useFoo(Foo f)
>> {
>>   auto x = f.prop;
>>   f.prop = 5;
>>    auto y = f.prop();  // also allowed
>>   f.prop(8);  // ditto
>> }
>
> Ok, so far so good.
>
>> 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. 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.
>
>> 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)();
> }
>
> 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?
>

It is. A duality like this is bad for language. Should you write foo.bar  
or foo.bar()?
If the former, as you insist, then why not force it? If the latter, then  
it is not a property anymore. It is a language hack right now!

Sergey's proposal is great because it is simple, expressive, sound and it  
removes the ambiguities that are present now.


More information about the Digitalmars-d-announce mailing list