Revised RFC on range design for D2

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Sat Sep 27 06:56:42 PDT 2008


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?

> void useFoo(Foo f)
> {
>   auto x = f.prop;  // OK
>   f.prop = 5;  // OK
> 
>   auto y = f.prop();  // syntax error, function expected
>   f.prop(8);  // syntax error, function expected
> 
>   int z = f.meth();  // OK, the delegate is called
> }
> 
> 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
> 
> With this, you receive an additional freedom which comes from removing 
> the ambiguity.  Imagine I want my personal hell:
> 
> class Hell
> {
>   private enum random = 666;
>   private inject property size_t realLen(T)(T[] any)
>   {
>     return random;
>   }
>   void tellTheTruth(string s)
>   {
>     writefln("real length of '%s' is %s", s, s.realLen);
>   }
> }
> 
> Here I've injected a useful property into all arrays but the injection 
> is private to my hell only so I can pretend there's still paradise 
> around.

I can imagine you want your personal hell, but I hardly can understand 
its usefulness to you or the rest of us :o).


Andrei


More information about the Digitalmars-d-announce mailing list