On Sun, 10 Feb 2013 07:09:52 -0500, Robert <jfanati...@gmx.at> wrote:
Ok, at the very first I have to make clear that my DIP is about changing
the actual specification, not trying to make the implementation to match
the specification, because in my view of things, the specification is
the problem.
Properties in my proposal are no longer about optional parentheses ore
forbidden parentheses. Properties are a concept hat benefits from the
fact, that parentheses are optional, but would work either way.
We don't need a feature to implement encapsulation, it's quite possible
without property specification. And your proposal does not guarantee
encapsulation anyway.
In the grand scheme of things, the fact that a range's front accessor
is a
property or a function is not technically important. But front being a
property IS important for specific uses. You can't have it so that
front
is a function only when using it as a range, and a property when using
it
as a delegate getter.
In my DIP a property is a function and they behave the same, except that
prop=5; calls prop(5); if prop is a property.
Then why do we need special syntax? I don't see the point. This is just
back to D1 properties.
>> In fact, the only case where a properly-implemented @property would
be
>> required on a getter is for delegate properties. I would argue that
if
>> @property worked correctly, it would be possible and correct to
require
>> r.front to be a property in that template.
> I don't understand, what is the exact problem with: r.front()()?
Despite
> not matching the specification regarding no parentheses for
properties?
The problem is, isInputRange does not require that it is a function, but
you ARE requiring that by specifying arbitrary rules.
I think this has to be fixed, because it solves all ambiguities and
encourages good design.
And who says what good design is? What if good design means low
performance? What if performance is more important? How can you say you
know the goals of every possible implementable object and whether
encapsulation is entirely necessary for it? You are holding hostage a
syntax feature on the concession that it play nice with your "requiring
function call" rules.
I don't think D should be dictating everything about how you write your
properties and methods. This is a systems language, not a nanny language.
Imagine an infinite range (one which never ends), that returns exactly a
specific delegate. Such a range could be implemented:
struct infiniteDelegate
{
int delegate() front;
enum empty = false;
void popFront() {};
}
It would, based on the current definition, yes. But what is it good for?
I think you miss the point then. You can't dismiss arguments because they
don't fit your narrative. This is a corner case, and not a far-fetched
one.
Why not simply write:
struct infiniteDelegate
{
int delegate() front();
bool empty() @property { return false; }
void popFront() {};
}
Because then I have to do:
id.front()();
To call the delegate. Not what I wanted to design. You are calling into
question my design because it doesn't suit your DIP. Why is your DIP more
important than my design?
Actually, that is not true. Check out the definition of
hasAssignableElements:
http://dlang.org/phobos/std_range.html#.hasAssignableElements
By your requirements, hasAssignableElements!(T[]) would necessarily
always
be false, since UFCS properties are banned, so array.front is not a
property. You are saying, I can't assign to the front element of an
array. That doesn't sit well with the rest of array's API.
Not true, the current definition of front for arrays is:
@property ref T front(T)(T[] a);
You are right, I did not look it up.
which would still work just the same, if you removed @property.
Right, the setter is not the reason we need @property on this, it's the
getter. And only for delegate arrays. I should not have brought this
example as a reason for UFCS setter properties.
Strings are interesting as front returns a non ref dchar (obviously),
but they have no writable front anyway. If you would really have a use
case where you need an actual setter/getter for an array for example,
just do proper encapsulation in a struct/class. If you don't do that,
your setter could be bypassed anyway so the design is questionable at
best. (Which you could still achieve via alias this, if you really
wanted that.)
Right, strings are an exception, because they are not treated like
arrays. A setter for front would be incorrect for strings.
Note also that you can have struct-qualified properties (at least you
should be able to, it seems Andrei's DIP does not allow it, but it's not
at odds with UFCS). Those are just about equivalent to module-level
properties, they just require specifying the struct name (and people
have
used this in clever ways to achieve good readable results).
Hmm, no real difference to struct/class properties:
import std.stdio;
int i;
void main() {
int i;
i=8;
writeln(".i: ", .i);
writeln(".i: ", testglobal.i);
}
Prints 0 both times. (The file was named testglobal.d)
I don't know what this example is trying to prove. I don't see any
properties here.
A ref property pretty much behaves EXACTLY like a field.
Exactly that is why I don't consider it a property. :-)
If it's not a property, it does not behave like a field. If it is a
function, then it can behave like a field for all cases except for the
delegate case.
> The current thinking instead seems to be that properties are just
> syntactic sugar and the level of encapsulation is business that is
left
> to the developer.
I don't think that SHOULD be D's business. Encapsulation should be
possible, encouraged, but not dictated.
It is not dictated, it is just encouraged and possible. If you don't
need encapsulation, don't call it a property. Nothing changes. You even
have a way out, if you first considered it a property with proper
set/get and later on you decide that this is not really needed, you can
drop it, no code will break, you just can not go back. But that was your
decision the moment you gave up @property.
Your design dictates that if you want field-like syntax, you have to agree
to arbitrary rules regarding ref, and you can't do it with UFCS. Such
rules are pretty much arbitrary, because there is no hidden meaning to a
property, they are just functions. The only benefit is the readability
and the 'human' meaning. Because instead of calling my function setX, I
can just call it x, and you have to use the x = ... to call it.
But you want to assign some guarantees that really aren't guarantees, they
are conventions. In the end, they just get in the way, and your
requirements can't achieve the type of guarantees you want.
> My thinking on the other hand is, that properties are the method of
> encapsulation, so they should ensure it. If something does not, it is
> not a property, which leads to a very clean design of properties.
Such a design is entirely possible today, even if ref properties exist,
even if *properties* didn't exist. Why must you use ref properties just
because they are available?
You don't, but their availability is no gain at all, because you would
have exactly the same if you removed @property, just the concept of a
property is screwed. If you want @property qualified ref returning
functions, then you also want UFCS properties, and my point is that
there is no point to it.
Your concept of property is that they are just functions. But we already
HAVE functions. There is no reason to have a language feature that says
"this is a property" unless it dictates the *syntax*. It is up to the
designer of the type to decide how it's parts are called, it should not be
up to the caller. Leaving it up to the caller results in unnecessary
obfuscation, and hidden meanings where none was intended.
There is actually no real need for properties, they are functions, they
can be called like functions. We can get along just fine if we have to
write:
setFoo(x);
instead of
foo = x;
If there is any reason to have a @property language feature, it's for
syntax, not for design.
Note that the reader/user of code is never guaranteed that they are
working with properly encapsulated code. A property looks like a field,
and a field is NOT encapsulated. So any compiler/language guarantees of
encapsulation with properties are moot.
My point is that it is wrong that a property should look like a field,
this just causes confusion, because people mix it up and forget about
encapsulation. Just stand to the fact that it is no field. If you want a
field, use a field or a method returning ref, don't use @property.
So there will be guaranteed to have a proper encapsulated field, the
moment they see @property, but what is more important is, that the
provider of the code can be sure that he/she got encapsulation right as
long as he/she does qualifies something with @property.
But they don't see property:
auto x = obj.y; // no @property in sight.
"guarantees" of encapsulation are easily thwarted:
struct NotEncapsulated
{
int x;
@property int y() { return x;}
}
-Steve