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