Taking address of properties

Steven Schveighoffer schveiguy at yahoo.com
Sat Feb 9 17:51:28 PST 2013


On Fri, 08 Feb 2013 16:45:58 -0500, Robert <jfanatiker at gmx.at> wrote:

> First of all, thanks for this very insight full discussion. I start to
> understand the other side. :-)

You are welcome!  I also am learning things and shaping my opinions based  
on these discussions.

> On Fri, 2013-02-08 at 15:13 -0500, Steven Schveighoffer wrote:
>> On Fri, 08 Feb 2013 14:05:40 -0500, Robert <jfanatiker at gmx.at> wrote:
>>
>> > all it states that you can get the current element by issuing:
>> > 	r.front
>> > which would still be possible with the optional parentheses of DIP23.
>>
>> Technically this is true.  But the expectation is that r.front is a
>> property/field, not a function.  That aspect is difficult to capture in  
>> a
>> template, especially in the current implementation where @property on a
>> getter is essentially redundant info.
> In a template you should not care what it actually is, as long as this
> works:
> 	auto h=r.front;
> (stolen from the implementation of isForwardRange), if I understood your
> argument correctly.

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

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() {};
}

Such a range would fit the definition of input range, but unlike an array,  
r.front() is how you call the delegate, not r.front()().

Making a consistent interface is not possible without @property.

>> Module level properties pose an issue, because @property does not
>> designate whether a property is a getter or a setter.  In particular, a
>> single-arg property function could be considered both a module property
>> setter, or a UFCS property getter.
>>
>> So your issue is not really that UFCS properties are wrong, it's that
>> disabling module-level properties is wrong.  I agree with you, but at  
>> the
>> same time, module level properties are not as common or useful as UFCS.
> Sure UFCS for functions, I suggest that UFCS for properties does not
> make a lot of sense. (If you apply my definition of a property and
> accept simple functions with optional parentheses as better way.)

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.

> I am sorry, I don't understand what you mean here with:
>> In fact, one could argue they are more confusing since module scope is  
>> one
>> of the only scopes that can be obscured.

int x;

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.

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

>
>>
>> There are other possible solutions, such as designating something as a
>> getter specifically, or adding more syntax (i.e. decorating the first
>> parameter as 'this' for a module-level UFCS getter).  But for now, the
>> easiest thing is to disallow one or the other, and since UFCS properties
>> are pretty much essential in Phobos, he's disabling the module level
>> properties.
>>
>> The 42.fun = 43 example, just about everything is wrong with that.
>>
>> Look here is another function that D "allows":
>>
>> void increment(int x);
>>
>> What is that exactly supposed to do?
>>
>> 42.increment(); // what?
>> increment(42); // what?
>>
>> Design and naming of functions is never going to be a problem that the
>> compiler can solve.
>
> Point taken. But my point is, that with optional parentheses UFCS
> properties are not needed, so the cleaner solution is to forbid UFCS
> properties. (See my DIP for further reasoning when it is ready)

What about setters?

>>
>> My point on that was, if something works but is not supposed to, we
>> shouldn't have to worry about keeping that code working.  @property in  
>> its
>> current form is NOT implemented as it was designed.  There is no
>> requirement to keep existing behavior that doesn't correctly work.
>>
>> In the example given, @property is supposed to ban the use of  
>> parentheses
>> according to the spec, but it doesn't.  In fact, in the case of a
>> @property that returns a delegate, it REQUIRES the extra parentheses.
>> This is a bug, and not something to try and keep working.
> Despite being inconsistent with the specification, what are the problems
> with that?

I'm not saying it's a problem, I suppose it could be considered by some,  
desirable to require the extra parentheses.  I haven't heard from that  
person yet.

But "being backwards compatible" is not a good reason when you are talking  
about incorrect behavior.  It would have to be because that is a desirable  
feature.  Frankly, if that was the case, I think we would never have  
introduced @property.

>>
>> On the other hand, ref @properties is NOT a bug, it functions as
>> designed.  Whether to remove it or not is certainly a discussion we can
>> have, but it's not buggy behavior.  See the difference?
>
> But the documentation of properties: http://dlang.org/property.html
> in the section about user defined properties also states in the very
> first sentence:
> 	 Properties are functions that can be syntactically treated as
> 	 if they were fields or variables.
>
> which is clearly not true at the moment. If this sentence got removed
> and replaced with a big fat warning that properties are not exchangeable
> with fields, this would be the least that should be done.

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?

A ref property pretty much behaves EXACTLY like a field.

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

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

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


More information about the Digitalmars-d mailing list