View mode: basic / threaded / horizontal-split · Log in · Help
January 05, 2006
Re: Property syntax revisited
On Thu, 5 Jan 2006 03:39:24 +0000 (UTC), S. Chancellor wrote:

> I don't know that I like the idea of having properties accept more than
> one type input.  I think they should use the normal type conversion
> rules if the property doesn't accept the type of data you want to shove into
> it.

Why?

And as a side point, I would really like to be able to specify abnormal
type conversions that are called by the compiler on assignment.

-- 
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 3:22:11 PM
January 05, 2006
Re: Property syntax revisited
Derek Parnell wrote:
> 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)); }
>   }

I proposed something similar to this many ages ago.  Mine looked like:

# class Foo {
#   property int height {
#     int _height;
#     int get () { return _height; }
#     int set (int x) { return _height = x; }
#     int set (char[] x) { return _height = toInt(x); }
#   }
# }

If I remember right.  I'm not sure how I feel about the reflective style, where property 
'height' has an auto-generated storage of '_height' as mentioned in another post, but it 
does solve a problem.  Maybe the syntax should be more like what you suggest, but with the 
gettor not concernings itself with type (in other words, the property is considered 
strongly typed for get purposes).  So, something like:

# property int height {
#   get { return _height; } // leave out to make input-only
#   set (int x) { _height = x; } // leave out to make read-only
#   set (char[] x) { _height = toInt(x); } // user-defined implicit conversion
# }

No redundant type information, yet we get keywords... that's one notable downside, 
especially the keywords 'get' and 'set' which can make perfectly good sense as collection 
object methods.

-- Chris Sauls
January 05, 2006
Re: Property syntax revisited
Chris Sauls wrote:
> Derek Parnell wrote:
> 
>> 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)); }
>>   }
> 
> 
> I proposed something similar to this many ages ago.  Mine looked like:
> 
> # class Foo {
> #   property int height {
> #     int _height;
> #     int get () { return _height; }
> #     int set (int x) { return _height = x; }
> #     int set (char[] x) { return _height = toInt(x); }
> #   }
> # }
> 
> If I remember right.  I'm not sure how I feel about the reflective 
> style, where property 'height' has an auto-generated storage of 
> '_height' as mentioned in another post, but it does solve a problem.  
> Maybe the syntax should be more like what you suggest, but with the 
> gettor not concernings itself with type (in other words, the property is 
> considered strongly typed for get purposes).  So, something like:
> 
> # property int height {
> #   get { return _height; } // leave out to make input-only
> #   set (int x) { _height = x; } // leave out to make read-only
> #   set (char[] x) { _height = toInt(x); } // user-defined implicit 
> conversion
> # }
> 
> No redundant type information, yet we get keywords... that's one notable 
> downside, especially the keywords 'get' and 'set' which can make 
> perfectly good sense as collection object methods.
> 
> -- Chris Sauls

<rant>
What is it with you people and the dependence on keywords? =P  You only 
need a special context-dependent identifier - this is NOT A KEYWORD. 
Keywords are language tokens and can only be used for the one thing that 
they mean.  OTOH, a special context-dependent identifier (as I call it, 
I guess) means that the compiler tests the name of the identifier given 
for a special word only within certain contexts.

In this case, when getter/setter methods are defined within a property 
block, the identifiers "get" and "set" have special meaning and are not 
just regular identifiers anymore.  HOWEVER, EVERYWHERE ELSE THEY HAVE NO 
SPECIAL MEANING.
</rant>

Not blowing up on you particularly, Chris. =)
January 05, 2006
Re: Property syntax revisited
On Thu, 05 Jan 2006 00:46:02 -0600, Chris Sauls wrote:

> I proposed something similar to this many ages ago.  Mine looked like:
> 
> # class Foo {
> #   property int height {
> #     int _height;
> #     int get () { return _height; }
> #     int set (int x) { return _height = x; }
> #     int set (char[] x) { return _height = toInt(x); }
> #   }
> # }
> 
> If I remember right.  I'm not sure how I feel about the reflective style, where property 
> 'height' has an auto-generated storage of '_height' as mentioned in another post, but it 
> does solve a problem.  Maybe the syntax should be more like what you suggest, but with the 
> gettor not concernings itself with type (in other words, the property is considered 
> strongly typed for get purposes).  So, something like:
> 
> # property int height {
> #   get { return _height; } // leave out to make input-only
> #   set (int x) { _height = x; } // leave out to make read-only
> #   set (char[] x) { _height = toInt(x); } // user-defined implicit conversion
> # }

However, there is no necessary requirement for a property to be implemented
by just a single internal (private?) variable. Also, other members in the
class might deal with the internal property variables in a more efficient
manner than using the get/set paradigm.

Ok, so here's another refinement ...

 private {
   float A;
   long  B;
 }
 property goofy {
    out (float) { goofy = cast(float)B + A; }
    in  (float) { B = cast(long) toInt(goofy);
                A = goofy - cast(float)B;}
 }
 void someFunc(long x)
 {
     if (B > 0) B *= x;
 }

Sure this is contrived, but you get my point.

I imagine the purpose of properties is to totally divorce the
implementation from the usage. Such that the 'public' face of the property
is a float, for example, but the implementation can change over time
without haven't to change any referencing source code. The implementation
can start off being a simple, single float variable but later can change to
some complex function and all the source code that references the property
doesn't have to be modified.

> No redundant type information, yet we get keywords... that's one notable downside, 
> especially the keywords 'get' and 'set' which can make perfectly good sense as collection 
> object methods.

So maybe 'gettor' and 'settor' as special and unusual words?

-- 
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 6:01:22 PM
January 05, 2006
Re: Property syntax revisited
Sean Kelly skrev:
> S. Chancellor wrote:
<snip>
> 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.
> 

My $0.02 (I like that one :) ).

1. IMHO it is bad to be able to call both as function and as property, 
it confuses adopters.
2. Breaking backward compatibility for properties is too late(?).
3. I want more syntactic sugar!

Today we have
int length(char[] str);
That can be called in two ways:
1. int bar = length(foo);
2. int baz = foo.length;

Why not add a "property" modifier, like this;
property int length(char[] str);
And now the 1. syntax is forbidden for the "function".

For extra syntactic sugar, if we have more then one parameter the rest 
of the parameters can be used as indexers. Like this:
property bool charIsNumber(char[] str, uint index) {
  return '0' <= str[index] && str[index] <= '9';
}
char[] foo = "Atari 520STe";
bool jupp = foo.charIsNumber[4];

So in 0.150 the property modifier gets adopted and non property marked 
properties gets depricated, then people start cleaning out their code, 
and by 1.0 everything is nice and jolly :).

// Fredrik Olsson.
January 05, 2006
Re: Property syntax revisited
"James Dunne" <james.jdunne@gmail.com> wrote in message 
news:dphugm$11vq$1@digitaldaemon.com...
> 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?

I just hadn't considered it. Makes sense to allow that.

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

I won't contradict you - it is quirky, but I was trying to placate those who 
might gasp at the propsect of introducing yet more keywords. Once you 
realise that in fact 'get' and 'set' would only have special meaning within 
the property block, and that they remain valid identifiers elsewhere, it's 
ok.

The other thing is what name to use for the compiler-generated setter 
parameter? 'value' is the obvious choice. That the compiler has to generate 
a magic variable at all shouldn't be an issue, since there's a precedent for 
this with variadic functions ('_arguments' and '_argptr').

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

Like methods, yes.

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

Any attempt to define a) a setter with an argument type that doesn't match 
that of the getter return type, or b) a getter with a return type that 
doesn't match that of the setter argument type, would be an error.

Better?

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

The same rules that apply to methods should apply to properties.

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

Yes, that's clearer.

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

I should have said with a "simple property" block, since there's no backing 
store variable to refer to until compilation.

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

Point taken, although if you've read some of the other replies, you'll see 
people are inferring that this would require them to be keywords.

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

It's redundant until the class writer decides to perform more complex 
operations within the accessor functions (such as resizing a window or 
repainting a shape). But yes, if it's just going to update a private field, 
and it's read/write, then you may as well use a public field. Unless there's 
extra value in tagging something as a property (perhaps for the benefit of 
an IDE or Ddoc documentation).

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

Maybe something analogous to an alias:

   property Height _height;
January 05, 2006
Re: Property syntax revisited
Sean Kelly wrote:
> 
> 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.
> 

I find it really useful too, but wouldn't agree on the unchanged part.
int x;

and replace it with:

int x(){return ...}
int x(int ...

this code will break:

void bla(inout int v);

bla(x);

I really wish there was a reasonable way of solving this problem.
Not ideal but maybe translating the above code to:

int __x = x();
bla(__x);
x(__x);
January 05, 2006
Re: Property syntax revisited
Fredrik Olsson wrote:
> My $0.02 (I like that one :) ).

OK, here is my 0.02kn (currency where i come from and < $0.02) :)

> 
> 1. IMHO it is bad to be able to call both as function and as property, 
> it confuses adopters.
> 2. Breaking backward compatibility for properties is too late(?).
> 3. I want more syntactic sugar!
> 
> Today we have
> int length(char[] str);
> That can be called in two ways:
> 1. int bar = length(foo);
> 2. int baz = foo.length;
> 
> Why not add a "property" modifier, like this;
> property int length(char[] str);
> And now the 1. syntax is forbidden for the "function".
> 

I am strongly in favor for adding extendable properties to *all* types 
and this syntax is as good as any other sugested.

> For extra syntactic sugar, if we have more then one parameter the rest 
> of the parameters can be used as indexers. Like this:

But this isn't....

> property bool charIsNumber(char[] str, uint index) {
>   return '0' <= str[index] && str[index] <= '9';
> }
> char[] foo = "Atari 520STe";
> bool jupp = foo.charIsNumber[4];
> 

...beacuse the rest of the parameters are in 99% of the cases not going 
to semanticaly be indexes.
January 05, 2006
Re: Property syntax revisited
Fredrik Olsson wrote:
> Sean Kelly skrev:
> 
>> S. Chancellor wrote:
> 
> <snip>
> 
>> 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.
>>
> 
> My $0.02 (I like that one :) ).
> 
> 1. IMHO it is bad to be able to call both as function and as property, 
> it confuses adopters.
> 2. Breaking backward compatibility for properties is too late(?).
> 3. I want more syntactic sugar!
> 
> Today we have
> int length(char[] str);
> That can be called in two ways:
> 1. int bar = length(foo);
> 2. int baz = foo.length;
> 
> Why not add a "property" modifier, like this;
> property int length(char[] str);
> And now the 1. syntax is forbidden for the "function".

I love it. Especially if it meant that properties could be added to any 
type (including built-in types), rather than just arrays.
Next ›   Last »
4 5 6 7 8
Top | Discussion index | About this forum | D home