properties

Steven Schveighoffer schveiguy at yahoo.com
Tue Jul 28 07:08:05 PDT 2009


On Mon, 27 Jul 2009 18:37:01 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail at erdani.org> wrote:

> Steven Schveighoffer wrote:
>> The "getter" notation that currently exists only has a few minor  
>> problems.  The most major of those problems is if the return value is a  
>> callable type, such as a delegate, you can't easily perform the call on  
>> the returned value.
>
> Thanks for a very lucid analysis!

You're welcome :)

>>  Being that it isn't very bad for the getter property, would it make  
>> sense to leave that functionality?  That is:
>>  1. A setter must be defined in the opSet_X(int x) form
>> 2. A getter can be a function with no required arguments, but this  
>> getter should not return callable types
>
> ... with zero arguments.

No, callable types period.  Note that this does not compile:

class A
{
     int delegate(int foo) wyda()
     {
         return delegate int(int foo) { return foo;};
     }
}


int main(string[] args)
{
     auto a = new A;
     auto b = a.wyda(5); // line 14
     auto c = a.wyda()(5);
     return 1;
}

[steves at steveslaptop files]$ dmd testme.d
testme.d(14): Error: function testme.A.wyda () does not match parameter  
types (int)
testme.d(14): Error: expected 0 arguments, not 1

commenting out line 14 compiles.

>
>> 3. A getter can be defined in the opGet_X() form, and then using X()  
>> will be the eqivalent of opGet_X()().
>>  There are small implications to leaving the existing getter syntax.   
>> Namely one can call a function not intended to be a getter in a  
>> property-like syntax, resulting in less-than-obvious code.
>
> This I don't agree with. I am very happy that I define popFront() as a  
> method and then call it without parens.

Knowing that you can call functions without parens, seeing code like:

r.popFront;

it's obvious that popFront is a function, not a property.

But, do you agree that this code looks less-than-obvious?

auto x = flush;

is flush a flag saying flushing should occur?  is it a function that  
flushes something, and returns the success?  I agree that the bizarre  
factor is not as bad as with setters, but it's still not as  
self-explanatory as if you know that something without parens must be a  
property for the compiler to accept it.

Also, without a dedicated property syntax for setters, you have the  
problem mentioned above with callable types.  At the very least you need  
the alternate syntax, the automagic properties for zero-arg functions are  
optional.

>
>>  Also, this distinction will be very hard to explain to newbies ("how  
>> come a getter is defined as x(), but a setter has to be opSet_x(...)?).
>
> I don't see that as a problem. You just explain that the trailing () is  
> not necessary, and then you tell them to define opSet_x if they want to  
> enable obj.x = y.

Perhaps.  I admit that I don't have any real evidence to support my claim,  
but I don't think you do either ;)

>
>> The more I look at it, the more I like the keyword solution.  I do find  
>> the C#-like syntax which groups properties together appealing, but I  
>> think you only absolutely need that if you are going to have  
>> context-keywords, which I DON'T think we need.  I do find the whole  
>> construct of C# properties tedious to type.
>>  With a keyword attribute, you could even group your properties  
>> together to save on typing/ugliness:
>>  property
>> {
>>    int x() {}
>>    void x(int n) {}
>>    bool empty() {}
>> }
>
> Not a fan, but this would work. I just don't see why I need to go  
> through with it.

Let's separate this problem into two sections:

1. do we have to hint to the compiler that a function is a property or not?

I think we do, otherwise, we have the strange setter anomalies, and the  
inability to return delegates from getters.  If you think this is not the  
case, state your arguments and solutions to those problems.  I don't think  
the compiler can tell if something is meant to be a property or not by  
looking at it.

2. Assuming #1 is true for either getters and/or setters, what should the  
hints be?

This is more of a bikeshed issue, but there are some technical issues to  
consider (- = negative, + = positive):

For an opSet style syntax (e.g. int opSet_foo()):
  - There is a possible conflict between opSet_foo and foo.  Since it would  
be the only operator function where the calling syntax is also valid  
symbol.  i.e. opAddAssign is called via +=, which can't be a valid  
symbol.  The compiler absolutely has to forbid this, which might be tough  
to implement.
  - The meaning is a bit cryptic, kind of like opApply.  I understand that  
it follows in line with other operators, so you might realize it is  
special, but it's not obvious that something is a property (this is really  
a bikeshed issue).
  + Because the function is of a different form than the property call, you  
can use it as a function easily.  For example, easy to get a delegate to  
it, just &opSet_foo.
  + no changes to parser!  No new keywords (some people value this, but I'm  
not really one of them)

For a new keyword-style syntax (e.g. property int foo()):
  + Much easier for the compiler to resolve a conflict, since you are  
directly declaring the called symbol.
  + Easier to understand that foo is a property than with opSet_foo, and  
easier to know how to call it.
  - If you wanted to use the property as a function (for example, get a  
delegate to the property), it might be more difficult.  For example, if a  
property is "property ref int foo()", &foo might give you the address of  
the returned value.  I don't really know a great solution to this problem,  
maybe a cast?  Maybe you forgo the ability to take the address of the  
return value, and just have it always be a delegate?
  - new keyword (some people might not like this, I don't really have a  
problem with it).
  + Easy to annotate groups of properties by enclosing them in an attribute  
block.

------

One more point.  From my point of view, the readability of the code, and  
obvious meaning of the code to a user of the code is more important than  
the ease of development.  I've always been a fan of verbose function names  
and variables which describe what the function/variable is rather than  
short easy to type names.  For instance I loathe the module structure of  
phobos, simply because the module names are too terse.  For me to try and  
find something, it's not obvious.

So to that point, I think it's more important to make the readability and  
self-explanatory nature of properties better than to make them easier to  
declare.  Remember, you only define them once, but you use them over and  
over.  Where is it better to save time, on reading the docs or on writing  
the declaration?

-Steve



More information about the Digitalmars-d mailing list