Revised RFC on range design for D2
Sergey Gromov
snake.scaly at gmail.com
Fri Sep 26 09:25:08 PDT 2008
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
}
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. 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() {...}
}
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.
More information about the Digitalmars-d-announce
mailing list