January 05, 2006
Derek Parnell <derek@psych.ward> 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)); }
>  }
> 
>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() );

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

-- 
Email works.

January 05, 2006
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
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
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
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
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
"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
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
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
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.