Taking address of properties

Robert jfanatiker at gmx.at
Sun Feb 10 04:09:52 PST 2013


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.

Reducing properties to functions with no parentheses is just not getting
it right as we can see with the problems we have.


> 
> 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.

> 
> >> 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.
> 
> 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?
Why not simply write:
struct infiniteDelegate
{
      int delegate() front();
      bool empty() @property { return false; }
      void popFront() {};
}

Where the body of front for example can ensure that the delegate is
actually set and not null or can change it if necessary, ...
I haven't applied @property to front in this example, because it would
not change anything, it would be required though if you provided a
setter and wanted to have front=something; work. Whether or not you
apply @property to read-only functions, depends on your use case, if you
want proper encapsulation, you would add @property and in case you want
a writable front at some time, you would add a setter. If you don't
consider encapsulation necessary, you would probably do not add
@property and return a ref if it has to be writable sometime.

> 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);

which would still work just the same, if you removed @property.

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.)

> void foo()
> {
> 
>     int x; // allowed
> 
>     x = 5; // applies to local scope, not module
>     {
>        int x; // error!  shadows outer scope x.
>     }
> }
> 
> So the point is, a global property could possibly be obscured if you  
> declared a local variable with the same name.

Same for instance variables and member functions.

> 
> 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)

> It certainly is true.  They can be treated like fields for getting and  
> setting, and I think "syntactically" means you access them like you would  
> access a field.
> 
> You might say "yeah, but you can't do ++ on them!", but you can't do that  
> to a const field either.  Should const fields be considered fields?

Well that's probably what was meant by this statement, but obviously it
was misunderstood by me and many others. It suggests that you can use
public fields if you would have required trivial set/get methods. (I
even found a blog post by someone who was bashing against Java how silly
they are and how cool D is, because we don't need trival set/get
methods)

> 
> A ref property pretty much behaves EXACTLY like a field.

Exactly that is why I don't consider it a property. :-)
> 
> > 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. 

> 
> > 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.

> 
> 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.
> 
> -Steve

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.





More information about the Digitalmars-d mailing list