July 27, 2009
On Mon, 27 Jul 2009 15:30:17 -0400, bearophile <bearophileHUGS@lycos.com> wrote:

> Steven Schveighoffer:
>> property
>> {
>>     int x() {}
>>     void x(int n) {}
>>     bool empty() {}
>> }
>
> An alternative:
>
> property(x) {
>     ... // or getter and/or setter
> }

No, that is a different proposal.  All I was saying is if property is an attribute, then like other attributes (const, etc), code like this:

property int x() {}
property void x(int n) {}
property bool empty() {}

can be rewritten as above.

-Steve
July 27, 2009
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! So let me give an example:

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

void main(string[] args)
{
    auto a = new A;
    auto b = a.wyda;
    writeln(typeof(b).stringof);
    auto c = a.wyda();
    writeln(typeof(c).stringof);
    auto d = a.wyda()();
    writeln(typeof(d).stringof);
    auto e = &a.wyda;
    writeln(typeof(e).stringof);
}

This program prints:

int delegate()
int delegate()
int
int delegate() delegate()

I agree that that's an issue. One can't currently implement transparently a property that returns a delegate taking no arguments. There's an extra () needed.

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

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

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

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


Andrei
July 27, 2009
Andrei Alexandrescu 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! So let me give an example:
> 
> class A
> {
>      int delegate() wyda()
>      {
>          return delegate int() { return 5; };
>      }
> }
> 
> void main(string[] args)
> {
>      auto a = new A;
>      auto b = a.wyda;
>      writeln(typeof(b).stringof);
>      auto c = a.wyda();
>      writeln(typeof(c).stringof);
>      auto d = a.wyda()();
>      writeln(typeof(d).stringof);
>      auto e = &a.wyda;
>      writeln(typeof(e).stringof);
> }
> 
> This program prints:
> 
> int delegate()
> int delegate()
> int
> int delegate() delegate()
> 
> I agree that that's an issue. One can't currently implement transparently a property that returns a delegate taking no arguments. There's an extra () needed.
> 
> >  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.
> 
> > 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.
> 
> >  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.
> 
> > 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.
> 
> 
> Andrei

Hi, I'm new here. A simple idea I've had is to simply use aliases for defining properties.

If you allow writing aliases as expressions, you have get properties. Then a simple extension to the syntax would also allow for writing set properties.

alias (a) property;
alias (a = n) property(n);

foo(property); // Get
property = 32; // Set

This virtually eliminates any problems with properties, and it doesn't require any new keywords. It won't break existing aliases either.
July 27, 2009
On Mon, Jul 27, 2009 at 7:33 PM, escalan<escalan@gmail.com> wrote:
> Hi, I'm new here. A simple idea I've had is to simply use aliases for defining properties.
>
> If you allow writing aliases as expressions, you have get properties. Then a simple extension to the syntax would also allow for writing set properties.
>
> alias (a) property;
> alias (a = n) property(n);
>
> foo(property); // Get
> property = 32; // Set
>
> This virtually eliminates any problems with properties, and it doesn't require any new keywords. It won't break existing aliases either.
>

Except if you want to do anything more complex in your setter/getter than a simple expression.
July 27, 2009
On Mon, Jul 27, 2009 at 7:49 PM, Jarrett Billingsley<jarrett.billingsley@gmail.com> wrote:
> On Mon, Jul 27, 2009 at 7:33 PM, escalan<escalan@gmail.com> wrote:
>> Hi, I'm new here. A simple idea I've had is to simply use aliases for defining properties.
>>
>> If you allow writing aliases as expressions, you have get properties. Then a simple extension to the syntax would also allow for writing set properties.
>>
>> alias (a) property;
>> alias (a = n) property(n);
>>
>> foo(property); // Get
>> property = 32; // Set
>>
>> This virtually eliminates any problems with properties, and it doesn't require any new keywords. It won't break existing aliases either.
>>
>
> Except if you want to do anything more complex in your setter/getter than a simple expression.

Also, if your suggestion really did just replace any accesses to the property with the aliased expression, there would be no way to override it in subclasses, it would be invisible to the debugger, etc.
July 28, 2009
Wed, 22 Jul 2009 23:10:53 +0200, Michiel Helvensteijn wrote:

> * Tuples (no dedicated syntax, no parallel assignment, no non-flattening tuples without workarounds, no returning tuples)

I'm planning to write a DIP on better tuple support.  Here is a brief overview of my ideas.  I think I'll blog a bit more before filing an actual DIP.

http://snakecoder.wordpress.com/2009/07/28/language-support-for-tuples-in-d
July 28, 2009
On Mon, 27 Jul 2009 18:37:01 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@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@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
July 28, 2009
Steven Schveighoffer wrote:
> On Mon, 27 Jul 2009 18:37:01 -0400, Andrei Alexandrescu 
>> ... 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@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.

Ok, thanks.

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

I think inferring meaning from the presence or absence of "()" is rather dicey.

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

Well I don't think so. To repeat what I wrote elsethread: foo = bar is rewritten into foo(bar) if and only if auto __x = foo, __x = bar works. This means, a setter only works if there's a corresponding getter. (Write-only properties be damned.)


Andrei
July 28, 2009
On Tue, 28 Jul 2009 10:16:16 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> I think inferring meaning from the presence or absence of "()" is rather dicey.

Really?  Then why name your functions things like empty, why not ex245, to make them look it up, making *sure* they know what the meaning is before they use it.  As one other person stated, they thought empty() emptied a range.

Being able to read code and understand what it means without resorting to documentation is the sign of a good choice of symbol names.  The presence or absence of parens is a hard-coded accepted meaning of field vs. function.  Properties build on this notion by making a virtual field that actually resolves to a function (but behaves like a field, and this is an important accepted meaning).  However, D does not allow intuitive names to be paired with the intuitive meaning of the presense or absence of parens, because you can't enforce it!  Remember my example with TimeSpans?  People will infer meaning from the presense or absense of parens whether you think it's a good idea or not.  You will never get away from 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.
>
> Well I don't think so. To repeat what I wrote elsethread: foo = bar is rewritten into foo(bar) if and only if auto __x = foo, __x = bar works. This means, a setter only works if there's a corresponding getter. (Write-only properties be damned.)

This is a band-aid fix, easily broken.

int select(int timeoutMS = -1); // method on a socket, for example

Hell, even my TimeSpan problem would still fail.

Also you are forgoing the ability to have overloaded setters, which could be useful.  Not to mention getters for delegates.

-Steve
July 28, 2009
Steven Schveighoffer wrote:
> On Tue, 28 Jul 2009 10:16:16 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> 
>> I think inferring meaning from the presence or absence of "()" is rather dicey.
> 
> Really?  Then why name your functions things like empty, why not ex245, to make them look it up, making *sure* they know what the meaning is before they use it.

I didn't say not to infer meaning from the name.

> As one other person stated, they thought empty() emptied a range.

Well it doesn't.

> Being able to read code and understand what it means without resorting to documentation is the sign of a good choice of symbol names.

Sure.

> The presence or absence of parens is a hard-coded accepted meaning of field vs. function.

I understand how some people want to derive meaning from obj.foo() versus obj.foo. I think they shouldn't in D. I mean D has had for years the behavior that you could drop the trailing empty parentheses.

> Properties build on this notion by making a virtual field that actually resolves to a function (but behaves like a field, and this is an important accepted meaning).

Not quite. C# has allocated a language feature for properties. Yet they allow you to write write-only properties, which do NOT behave at all like fields, and also read-only properties, which also don't behave like fields. Guess what - they both behave like functions. So their properties are an elaborate mechanism that is actually thoroughly unchecked, thus going back to what you could do by calling functions. So why the hell did they define the feature in the first place? Oh, for allowing people to write a.foo() instead of a.foo. You know what, that's a bit disappointing for an entire language feature.

> However, D does not allow intuitive names to be paired with the intuitive meaning of the presense or absence of parens, because you can't enforce it!  Remember my example with TimeSpans?  People will infer meaning from the presense or absense of parens whether you think it's a good idea or not.  You will never get away from 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.
>>
>> Well I don't think so. To repeat what I wrote elsethread: foo = bar is rewritten into foo(bar) if and only if auto __x = foo, __x = bar works. This means, a setter only works if there's a corresponding getter. (Write-only properties be damned.)
> 
> This is a band-aid fix, easily broken.
> 
> int select(int timeoutMS = -1); // method on a socket, for example
> 
> Hell, even my TimeSpan problem would still fail.

Well maybe you could change TimeSpan.

> Also you are forgoing the ability to have overloaded setters, which could be useful.  Not to mention getters for delegates.

Wait, overloaded setters do NOT make the thing behave like a field, but you were stating how nice that is a few paragraphs ago! So what is it that you think is good?


Andrei
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
Top | Discussion index | About this forum | D home