Jump to page: 1 25  
Page
Thread overview
Property syntax revisited
Jan 04, 2006
John C
Jan 04, 2006
S. Chancellor
Jan 04, 2006
Sean Kelly
Jan 05, 2006
John C
Jan 05, 2006
Fredrik Olsson
Jan 05, 2006
Ivan Senji
Jan 05, 2006
Fredrik Olsson
Jan 05, 2006
Ivan Senji
Jan 05, 2006
Don Clugston
Jan 05, 2006
Fredrik Olsson
Jan 05, 2006
Ivan Senji
Jan 05, 2006
John C
Jan 05, 2006
S. Chancellor
Jan 05, 2006
James Dunne
Jan 05, 2006
James Dunne
Jan 05, 2006
Derek Parnell
Jan 05, 2006
S. Chancellor
Jan 05, 2006
Derek Parnell
Jan 05, 2006
Chris Sauls
Jan 05, 2006
James Dunne
Jan 05, 2006
Chris Sauls
Jan 05, 2006
James Dunne
Jan 05, 2006
Derek Parnell
Jan 05, 2006
Chris Sauls
Jan 05, 2006
Kris
Jan 05, 2006
Derek Parnell
Jan 05, 2006
Kris
Jan 05, 2006
Chris Sauls
Jan 05, 2006
Kris
Jan 05, 2006
Kris
Jan 05, 2006
S. Chancellor
Jan 05, 2006
John C
Jan 05, 2006
Chris Sauls
Jan 05, 2006
John C
Simpler property syntax - was Re: Property syntax revisited
Jan 05, 2006
Chris Miller
Jan 05, 2006
Kris
Jan 05, 2006
Chris Miller
Jan 06, 2006
Kris
Jan 06, 2006
tj0258
Jan 06, 2006
Zeljko
Jan 06, 2006
Zeljko
January 04, 2006
As I see it, the problem with D's property syntax is that they're actually methods, and the compiler has to try to disamiguate between method and property calls/assignments, which it's not 100% successful at - sometimes you have to add a pair of parentheses '()' when using a property to stop the compiler from choking (for example, when used in conjunction with 'auto').

Another issue is that it introduces ambiguity in the way they are called, and users have no way of knowing how they are intended to be used - 'my.name("John")' or 'my.name = "John"'.

The other issue is that properties have the semantics of fields, not methods (even if, in the end, the compiler just generates the same code as for a method). They just don't feel like first-class citizens.

I'd like to suggest a new syntax that I think addresses these issues. The only downside is the addition of a new keyword, 'property'. But otherwise it's quite elegant and is only slightly more verbose than the current syntax (the keyword itself). It's basically a way of grouping a pair of getters and setters in a 'property block'.

Here's a class that utilises it.

    class Person {

        private float weight_; // Manually written backing store for
'weight' property

        protected void onWeightChanged() {
            // Warn of heart attack risk if above a certain weight
        }

        property weight { // 'weight' property block
            float() { // This defines the signature of the getter
                return weight_;
            }
            void(float value) { // This defines the signature of the setter;
                                        // setters must have a void return
type
                weight_ = value;
                onWeightChanged();
            }
        } // end 'weight' property block

        // In this property block, we don't provide definitions,
        // which tells the compiler to generate a backing store
        // and the definitions on our behalf.
        // Let's call it a 'simple property'.
        property height {
            float();
            void(float);
        }

        // property block with getter only
        property bmi {
            float() {
                return weight / (height * height);
            }
        }

    }

Some notes:
1) Any attempt to define a setter with an argument type that doesn't match
that of the getter return type would be an error (and vise versa).
2) Different protection attributes can be applied to the getter and setter,
as with methods.
3) For property blocks without manual definitions (as in the 'height'
example above), either the getter or setter signature can be omitted, making
them either read- or write-only, which distinguishes them from public
fields.
4) Within the scope of a property block, use of the property name itself is
legal, since the compiler knows to refer to the automatically generated
backing store (as opposed to introducing a recursive call).

No doubt there will be objections to this notation, so fire away. But I reckon it's a nice compromise between the C# and C++/CLI syntaxes (which require three contextual keywords: 'get', 'set' and 'value') and the current D syntax.


January 04, 2006
In article <dphgrp$nbt$1@digitaldaemon.com>, John C says...

> ....
>        property weight { // 'weight' property block
>            float() { // This defines the signature of the getter
>                return weight_;
>            }
>            void(float value) { // This defines the signature of the setter;
>                                        // setters must have a void return
>type
>                weight_ = value;
>                onWeightChanged();
>            }
>        } // end 'weight' property block

Your example seems a bit odd to me as the setter can have a different input type from the getter.  If you're going to go the way of implementing a whole property block it seems that they should have their type specified in the property area. In which case we might as well adopt the C# syntax for properties.

IE:

float weight_;
property float weight {
get {
return weight_;
}
set {
weight_ = weight;
}
}

If there is a requirement that a property be able to return differen types, the casting features of D should take over. IMHO.

-S.



January 04, 2006
S. Chancellor wrote:
> In article <dphgrp$nbt$1@digitaldaemon.com>, John C says...
> 
>> ....
>>        property weight { // 'weight' property block
>>            float() { // This defines the signature of the getter
>>                return weight_;
>>            }
>>            void(float value) { // This defines the signature of the setter;
>>                                        // setters must have a void return type
>>                weight_ = value;
>>                onWeightChanged();
>>            }
>>        } // end 'weight' property block
> 
> Your example seems a bit odd to me as the setter can have a different input type
> from the getter.  If you're going to go the way of implementing a whole property
> block it seems that they should have their type specified in the property area.
> In which case we might as well adopt the C# syntax for properties.  
> 
> IE:
> 
> float weight_;
> property float weight {
> get {
> return weight_;
> }
> set {
> weight_ = weight;
> }
> }
> 
> If there is a requirement that a property be able to return differen types, the
> casting features of D should take over. IMHO.

I think a property syntax is a reasonable idea so long as we don't lose the ability to use free functions as properties.  I'm finding it quite useful that I can even replace global variables with no-argument functions and leave all other code unchanged.


Sean
January 05, 2006
> Your example seems a bit odd to me as the setter can have a different
> input type
> from the getter.

No it can't. I do note in my original post that the types have to match.

> If you're going to go the way of implementing a whole property
> block it seems that they should have their type specified in the property
> area.
> In which case we might as well adopt the C# syntax for properties.

It was an attempt to avoid context-sensitive keywords, which Walter's not fond of. Hence type signatures in my design take the place of 'get' and 'set'.


January 05, 2006
"Sean Kelly" <sean@f4.ca> wrote in message news:dphn95$s0l$1@digitaldaemon.com...
> S. Chancellor wrote:
>> In article <dphgrp$nbt$1@digitaldaemon.com>, John C says...
>>
>>> ....
>>>        property weight { // 'weight' property block
>>>            float() { // This defines the signature of the getter
>>>                return weight_;
>>>            }
>>>            void(float value) { // This defines the signature of the
>>> setter;
>>>                                        // setters must have a void
>>> return type
>>>                weight_ = value;
>>>                onWeightChanged();
>>>            }
>>>        } // end 'weight' property block
>>
>> Your example seems a bit odd to me as the setter can have a different
>> input type
>> from the getter.  If you're going to go the way of implementing a whole
>> property
>> block it seems that they should have their type specified in the property
>> area.
>> In which case we might as well adopt the C# syntax for properties.  IE:
>>
>> float weight_;
>> property float weight {
>> get {
>> return weight_;
>> }
>> set {
>> weight_ = weight;
>> }
>> }
>>
>> If there is a requirement that a property be able to return differen
>> types, the
>> casting features of D should take over. IMHO.
>
> I think a property syntax is a reasonable idea so long as we don't lose the ability to use free functions as properties.  I'm finding it quite useful that I can even replace global variables with no-argument functions and leave all other code unchanged.

Yes, I find it useful too. But there's no reason why a property block couldn't be valid for modules as well.

>
>
> Sean


January 05, 2006
John C wrote:
> As I see it, the problem with D's property syntax is that they're actually methods, and the compiler has to try to disamiguate between method and property calls/assignments, which it's not 100% successful at - sometimes you have to add a pair of parentheses '()' when using a property to stop the compiler from choking (for example, when used in conjunction with 'auto').
> 
> Another issue is that it introduces ambiguity in the way they are called, and users have no way of knowing how they are intended to be used - 'my.name("John")' or 'my.name = "John"'.
> 
> The other issue is that properties have the semantics of fields, not methods (even if, in the end, the compiler just generates the same code as for a method). They just don't feel like first-class citizens.

Properties are meant to have the same semantics as methods, NOT fields.  They are made to have the same SYNTAX as fields.

I agree, they don't feel like first-class citizens in D.

> I'd like to suggest a new syntax that I think addresses these issues. The only downside is the addition of a new keyword, 'property'. But otherwise it's quite elegant and is only slightly more verbose than the current syntax (the keyword itself). It's basically a way of grouping a pair of getters and setters in a 'property block'.

> 
> Here's a class that utilises it.
> 
>     class Person {
> 
>         private float weight_; // Manually written backing store for 'weight' property
> 
>         protected void onWeightChanged() {
>             // Warn of heart attack risk if above a certain weight
>         }
> 
>         property weight { // 'weight' property block
>             float() { // This defines the signature of the getter
>                 return weight_;
>             }
>             void(float value) { // This defines the signature of the setter;
>                                         // setters must have a void return type
>                 weight_ = value;
>                 onWeightChanged();
>             }
>         } // end 'weight' property block

Why must the return value of the setter be void?  What if I want to chain my property setter calls in an 'a = b = c = d' manner?

Then if you change the void-return rule to allow returning any type, you must then define if that return type is required to match the implied type of the property.  It follows that it becomes increasingly more difficult to determine the actual type of the property.

Another note, it would be much clearer to the D beginner if he/she were required to name the getter method as "get" and the setter method as "set", instead of the quirky-looking identifier-removed function definition syntax proposed above.  Best to remain consistent with the rest of the language - it also makes implementation easier.

>         // In this property block, we don't provide definitions,
>         // which tells the compiler to generate a backing store
>         // and the definitions on our behalf.
>         // Let's call it a 'simple property'.
>         property height {
>             float();
>             void(float);
>         }

Does this mean that properties can be inherited and overridden?

> 
>         // property block with getter only
>         property bmi {
>             float() {
>                 return weight / (height * height);
>             }
>         }
> 
>     }
> 
> Some notes:
> 1) Any attempt to define a setter with an argument type that doesn't match that of the getter return type would be an error (and vise versa).

Lol. There is no vice-versa in this case. =P

> 2) Different protection attributes can be applied to the getter and setter, as with methods.

So, hypothetically, I can read from a property in public and perhaps write to it only in a child class?  What's the point of that?

> 3) For property blocks without manual definitions (as in the 'height' example above), either the getter or setter signature can be omitted, making them either read- or write-only, which distinguishes them from public fields.

This would make them read-only, write-only, OR read/write properties, not just either read-only or write-only.  Best to be clear about such things.

In fact, the notion of a field being read-only doesn't really apply here in the true sense of the return value being read-only.

> 4) Within the scope of a property block, use of the property name itself is legal, since the compiler knows to refer to the automatically generated backing store (as opposed to introducing a recursive call).

You mean use of the property name when defining a local variable to one of the setter/getter methods, right?  AFAIK, we don't allow such things in regular functions so this would be inconsistent with the rest of D.

> No doubt there will be objections to this notation, so fire away. But I reckon it's a nice compromise between the C# and C++/CLI syntaxes (which require three contextual keywords: 'get', 'set' and 'value') and the current D syntax.

Nobody says that "get" or "set" must be keywords (or contextual keywords).  They can be context-dependent special identifiers.

-------------------
Why not propose also a 'reflect' sort-of syntax, such that a public property may reflect the value of a corresponding private member without having to write redundant code.  I see a lot of situations like this in C#, where public properties simply reflect values of private members. It seems completely silly to write such redundant code as

C#:
property float Height {
	get { return _height; }
	set { _height = value; }
}

Your proposed D syntax:
property Height {
	float() { return _height; }
	void (float value) { _height = value; }
}

Why not reduce the potential for bugs in such a case by telling the compiler what you actually want to do?  I don't see any clean way to do this in addition to your syntax proposal, unfortunately.
January 05, 2006
n article <dphnia$si9$1@digitaldaemon.com>, John C says...
>
>> Your example seems a bit odd to me as the setter can have a different
>> input type
>> from the getter.
>
>No it can't. I do note in my original post that the types have to match.

It can as long as I type it twice.  If there's a restriction that it has to be what I typed the first time... then I shouldn't have to type it twice.
>
>> If you're going to go the way of implementing a whole property
>> block it seems that they should have their type specified in the property
>> area.
>> In which case we might as well adopt the C# syntax for properties.
>
>It was an attempt to avoid context-sensitive keywords, which Walter's not fond of. Hence type signatures in my design take the place of 'get' and 'set'.

True, but either way uses context-sensitive something.  The current
method doesn't require context sensitive anything.    If we're going to
introduce new semantic regions, and change the syntax for function
declarations within, we might as well introduce keywords for it.  Your method
just reuses keywords, for something they weren't intended,  which is
arguably more confusing.
-S.



January 05, 2006
S. Chancellor wrote:
> n article <dphnia$si9$1@digitaldaemon.com>, John C says...
> 
>>>Your example seems a bit odd to me as the setter can have a different
>>>input type
>>>from the getter.
>>
>>No it can't. I do note in my original post that the types have to match.
> 
> 
> It can as long as I type it twice.  If there's a restriction that it has
> to be what I typed the first time... then I shouldn't have to type it
> twice.
> 
>>>If you're going to go the way of implementing a whole property
>>>block it seems that they should have their type specified in the property
>>>area.
>>>In which case we might as well adopt the C# syntax for properties.
>>
>>It was an attempt to avoid context-sensitive keywords, which Walter's not
>>fond of. Hence type signatures in my design take the place of 'get' and
>>'set'.
> 
> 
> True, but either way uses context-sensitive something.  The current
> method doesn't require context sensitive anything.    If we're going to
> introduce new semantic regions, and change the syntax for function
> declarations within, we might as well introduce keywords for it.  Your method
> just reuses keywords, for something they weren't intended,  which is
> arguably more confusing.
> -S.
> 

Well said!
January 05, 2006
On Wed, 04 Jan 2006 20:00:53 -0600, James Dunne wrote:

> It seems completely silly to write such redundant code as
> 
> C#:
> property float Height {
> 	get { return _height; }
> 	set { _height = value; }
> }
> 
> Your proposed D syntax:
> property Height {
> 	float() { return _height; }
> 	void (float value) { _height = value; }
> }

And current D syntax:
  float Height() { return _height; }
  void Height(float value) { _height = value; }


> Why not reduce the potential for bugs in such a case by telling the compiler what you actually want to do?  I don't see any clean way to do this in addition to your syntax proposal, unfortunately.

Just playing here but something like this seems nice to me ...

  float _height;
  property Height {
     get float { Height = _height; }
     // Value must be zero or greater.
     set float { _height = fmax(0.0, Height); }
     set real  { _height = fmax(0.0, cast(float)Height); }
     set char[]{ _height = fmax(0.0, atof(Height)); }
  }

And assignment chaining would be achieved by calling the getter whenever
needed.

   a.Height = b.Height = "4.0";

would be equivalent to ...

   b.setHeight("4.0");
   a.setHeight( b.getHeight() );

-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
"A learning experience is one of those things that says,
 'You know that thing you just did? Don't do that.'" - D.N. Adams
5/01/2006 1:51:53 PM
January 05, 2006
James Dunne <james.jdunne@gmail.com> wrote:

>Why not propose also a 'reflect' sort-of syntax, such that a public property may reflect the value of a corresponding private member without having to write redundant code.  I see a lot of situations like this in C#, where public properties simply reflect values of private members. It seems completely silly to write such redundant code as
>
>C#:
>property float Height {
>	get { return _height; }
>	set { _height = value; }
>}
>
>Your proposed D syntax:
>property Height {
>	float() { return _height; }
>	void (float value) { _height = value; }
>}
>
>Why not reduce the potential for bugs in such a case by telling the compiler what you actually want to do?  I don't see any clean way to do this in addition to your syntax proposal, unfortunately.


I fully agree with your here.  I'm glad to find out I'm not alone in the
war against blank properties!  In fact .NET requires you to write blank
properties in some cases.  (IE:  passing a collection of classes to a
DataGrid, you can only specify property names for output.)
-S.

-- 
Email works.

« First   ‹ Prev
1 2 3 4 5