January 09, 2009
Nick Sabalausky wrote:
> A property setter is ALWAYS going to return nothing and

Both the getter and the setter should return an rvalue. Properties exist so that they are interchangeable with real member variables. Something that is possible with member variables MUST also be possible with properties, in a transparent way for any code outside the class.

For example:

	button.width = button.height = 50;	// makes a square button

Optimally, this should expand to either:

	button._set_width(button._set_height(50));

or

	button._set_height(50);
	button._set_width(button._get_height());

From the compiler point-of-view, the first is easier to implement.

> take in exactly one argument, of the same type as the property, and that value will ALWAYS represent the intended new value.

Also not true. It is fine to have method polymorphism for the setter.
You may want to define property set(int value), set(Bigint value) and
set(float value), all with different semantics.
January 09, 2009
Chad J wrote:
> I actually like the idea.
> 
> (...)
> 
> int nTimesVarRead = 0;
> 
> public property int var
> {
>     get
>     {
>         nTimesVarRead++;
>         return internalValue;
>     }
> 
>     set { internalValue = $; }
> }

That defeats one of the purposes of properties. A property is usually an accessor for some member variable. You have two concepts: the property and the member variable; they MUST be declared separately, since they may have different attributes.

For example, the underlying member variable may have any of public, protected or private visibility, while the property may also have any of public, protected or private visibility. Usually, the member variable is either protected or private, while the property is either public or protected.

Also, the class itself, and any inner scopes, may want to access the underlying member variable directly, without going through the property accessors.

> Perhaps, since the compiler knows the name of the property, the name of the generated internal value could just be the name of the property:
> 
> public property int var
> {
>     get { return var; }
>     set { var = $; }
> }

That is the question... the property is public, but var is private or protected? How does the class access var without triggering the property accessors?
January 09, 2009
On Fri, Jan 9, 2009 at 9:59 AM, Miles <_______@_______.____> wrote:
> Nick Sabalausky wrote:
>> A property setter is ALWAYS going to return nothing and
>
> Both the getter and the setter should return an rvalue. Properties exist so that they are interchangeable with real member variables.

Partly, but also properties exist to provide encapsulation of private state.
So you gotta be careful when you say they should always return an lvalue.
Returning a straight 'ref T' is pretty much the same as making the
member variable public,
in terms of the encapsulation it gives you.

class Foo {
  private int _data;
  ref int data() { return _data; }
  void data(int d) {
       data = d;
       do_something_very_important();
  }
}

auto foo = new Foo;
int*allyourdataisbelongtome = &Foo.data;

Bye bye encapsulation.  Now I can change your data all I want without you noticing.

Also it means if I later realize I actually wanted data to be a float internally, I still have to keep an int member around to satisfy any client code that depends on getting an integer lvalue back.

What I would like to see happen is that if a property setter doesn't return an lvalue, then the compiler will jigger things around to do everything in terms of calls to the setter.  If it does return an lvalue then it will use it directly.

> Something
> that is possible with member variables MUST also be possible with
> properties, in a transparent way for any code outside the class.
>
> For example:
>
>        button.width = button.height = 50;      // makes a square button

I agree that that should expand to something sensible, but that example doesn't actually require the setters to return an lvalue.  A regular rvalue is fine for that.

You'd only need to return an lvalue for something like:
      (button.height=50) += 3;

Or for something like   change_integer( button.height = 50 );  where
change_integer takes a  ref int.

Using the lvalue returned from a property assignment is really not that common I think.  Maybe I'm missing some big use case though.

On the other hand, things like ++x do get used as lvalues more commonly I think.    I'm fond of doing   ++x%=N as a way to do a wrapped increment.  :-)  In C++, anyway.  In D it gives me "x += 1 is not an lvalue".

--bb
January 09, 2009
"Miles" <_______@_______.____> wrote in message news:gk67hr$17d9$1@digitalmars.com...
> Nick Sabalausky wrote:
>> A property setter is ALWAYS going to return nothing and
>
> Both the getter and the setter should return an rvalue. Properties exist so that they are interchangeable with real member variables. Something that is possible with member variables MUST also be possible with properties, in a transparent way for any code outside the class.
>
> For example:
>
> button.width = button.height = 50; // makes a square button
>
> Optimally, this should expand to either:
>
> button._set_width(button._set_height(50));
>
> or
>
> button._set_height(50);
> button._set_width(button._get_height());
>
> From the compiler point-of-view, the first is easier to implement.
>

True, but my main point was, however the language ends up handling the details of property getters/setters, it's not going to be as general as ordinary functions, and thus certain aspects of the syntax can/should be simplified.

But regarding your examples up there, the first form might be easier for the compiler to implement, but I think the second would be overall better. You're absolutely right that properties need to be able to return an rvalue from an assignment, but I see no reason why that can't or shouldn't be transparent to the person writing the property.

>> take in exactly one argument, of the same type as the property, and that value will ALWAYS represent the intended new value.
>
> Also not true. It is fine to have method polymorphism for the setter.
> You may want to define property set(int value), set(Bigint value) and
> set(float value), all with different semantics.

I'm still not 100% convinced that we should be using properties to do type conversions, although I suppose it may have some legitimate uses...

I guess I'm just afraid of ending up with a situation where people start feeling compelled to make all of their properties explicitly compatible with every type under the sun. All of a sudden we'd be heading towards all-out dynamic typing, and start losing the benefits of static typing, and, and...then the sun explodes...or something...(I should stay off that slippery slope...)

But anyway, even with the possibility of a property handling multiple types, I still don't think it means we can't or shouldn't have a nicely trimmed syntax for the more typical cases:

property int x
{
    set { this = this.new; }
    get { return this; }

    set char[] { this = StringToInt(this.new); }
    get char[] { return IntToString(this); } // If we ever got
overload-on-return-value
}


January 09, 2009
"Bill Baxter" <wbaxter@gmail.com> wrote in message news:mailman.343.1231465331.22690.digitalmars-d@puremagic.com...
> On Fri, Jan 9, 2009 at 9:59 AM, Miles <_______@_______.____> wrote:
>> Nick Sabalausky wrote:
>>> A property setter is ALWAYS going to return nothing and
>>
>> Both the getter and the setter should return an rvalue. Properties exist so that they are interchangeable with real member variables.
>
> Partly, but also properties exist to provide encapsulation of private
> state.
> So you gotta be careful when you say they should always return an lvalue.

He said "rvalue", not "lvalue". I actually made that same mistake the first couple times I read it.


January 09, 2009
Bill Baxter wrote:
> On Fri, Jan 9, 2009 at 9:59 AM, Miles <_______@_______.____> wrote:
>> Both the getter and the setter should return an rvalue. Properties exist so that they are interchangeable with real member variables.
> 
> Partly, but also properties exist to provide encapsulation of private state. So you gotta be careful when you say they should always return an lvalue.

Wait! Read again what I said... getters and setters should return an *rvalue*, not lvalue. Everything else you said was based on the idea that accessors return lvalues, that wasn't what I said...

There are some very special conditions where the getter MAY return an lvalue. But nothing else. The setter always returns rvalues.

For example, if prop is a common property, defined as:

	public property int width {
	  get() { return m_width; }
	  set(Point value) { return m_width = value; }
	}

Then the following code:

	x.width += 5;

Should expand to something like (hopefully, optimized as far as possible):

	{
	  auto tmp = x._get_width();
	  tmp += 5;
	  x._set_width(tmp);
	}

On the other hand, if the getter is defined to return an lvalue, like
(tentative syntax):

	public property int width {
	  ref get() { return m_width; }
	  set(Point value) { return m_width = value; }
	}

Then the compiler should be able to optimize the same code further:

	x._get_width() += 5;

The same for member function calls if the property type is a structure or class.
January 09, 2009
On Fri, Jan 9, 2009 at 10:58 AM, Nick Sabalausky <a@a.a> wrote:
> "Bill Baxter" <wbaxter@gmail.com> wrote in message news:mailman.343.1231465331.22690.digitalmars-d@puremagic.com...
>> On Fri, Jan 9, 2009 at 9:59 AM, Miles <_______@_______.____> wrote:
>>> Nick Sabalausky wrote:
>>>> A property setter is ALWAYS going to return nothing and
>>>
>>> Both the getter and the setter should return an rvalue. Properties exist so that they are interchangeable with real member variables.
>>
>> Partly, but also properties exist to provide encapsulation of private
>> state.
>> So you gotta be careful when you say they should always return an lvalue.
>
> He said "rvalue", not "lvalue". I actually made that same mistake the first couple times I read it.

Wow.  You're right.  Maybe I need to change my font or something. Sorry for the rant about returning lvalues then!

--bb
January 09, 2009
On Fri, Jan 9, 2009 at 11:01 AM, Miles <_______@_______.____> wrote:
> Bill Baxter wrote:
>> On Fri, Jan 9, 2009 at 9:59 AM, Miles <_______@_______.____> wrote:
>>> Both the getter and the setter should return an rvalue. Properties exist so that they are interchangeable with real member variables.
>>
>> Partly, but also properties exist to provide encapsulation of private state. So you gotta be careful when you say they should always return an lvalue.
>
> Wait! Read again what I said... getters and setters should return an *rvalue*, not lvalue. Everything else you said was based on the idea that accessors return lvalues, that wasn't what I said...
>
> There are some very special conditions where the getter MAY return an lvalue. But nothing else. The setter always returns rvalues.
>
> For example, if prop is a common property, defined as:
>
>        public property int width {
>          get() { return m_width; }
>          set(Point value) { return m_width = value; }
>        }
>
> Then the following code:
>
>        x.width += 5;
>
> Should expand to something like (hopefully, optimized as far as possible):
>
>        {
>          auto tmp = x._get_width();
>          tmp += 5;
>          x._set_width(tmp);
>        }
>
> On the other hand, if the getter is defined to return an lvalue, like
> (tentative syntax):
>
>        public property int width {
>          ref get() { return m_width; }
>          set(Point value) { return m_width = value; }
>        }
>
> Then the compiler should be able to optimize the same code further:
>
>        x._get_width() += 5;
>
> The same for member function calls if the property type is a structure or class.


Ok!  I'm in agreement with you totally on all that.   Sorry for the lvalue/rvalue mixup.

--bb
January 09, 2009
Nick Sabalausky wrote:
> True, but my main point was, however the language ends up handling the details of property getters/setters, it's not going to be as general as ordinary functions, and thus certain aspects of the syntax can/should be simplified.

In this case, simplifying would be more complex.

Under the hood, when you define getters and setters, you are defining functions, and function overloading is an inherent feature of the language. In fact, the current "property" feature of D already supports many overloaded setters for different types, since they are just normal functions.

For example, consider the property definition:

	public property int width {
	  get() { return width; }
	  set(int value) { width = value; }
	  set(float value) { width = value + 0.5; }
	}

That would generate overloaded functions with different signatures, lets say that, under the hood, the compiler generates:

	int __get_width();
	int __set_width(int value);
	int __set_width(float value);

Then, when code that accesses the property is compiled, something that looks like

	width = x;

will, in fact, be threated as

	__set_width(x);

and so, the compiler will choose the appropriate __set_width() function with the signature that matches the above call.

So, restricting a property to have only a single setter will end up creating unnecessary restrictions for something that is already native to the language.

> You're absolutely right that properties need to be able to return an rvalue from an assignment, but I see no reason why that can't or shouldn't be transparent to the person writing the property.

They could, no problem.

> I'm still not 100% convinced that we should be using properties to do type conversions, although I suppose it may have some legitimate uses...

It is not just about type conversions... it is that the feature is already something natural for the language.

> But anyway, even with the possibility of a property handling multiple types, I still don't think it means we can't or shouldn't have a nicely trimmed syntax for the more typical cases:
> 
> property int x
> {
>     set { this = this.new; }
>     get { return this; }
> 
>     set char[] { this = StringToInt(this.new); }
>     get char[] { return IntToString(this); } // If we ever got
> overload-on-return-value
> }

Not for getters, please... the type of the getter should be the type of the property, or that would create a lot of complexity for the language (that is also the reason you don't overload functions based on the return type).
January 09, 2009
"Miles" <_______@_______.____> wrote in message news:gk68q1$19g1$1@digitalmars.com...
> Chad J wrote:
>> I actually like the idea.
>>
>> (...)
>>
>> int nTimesVarRead = 0;
>>
>> public property int var
>> {
>>     get
>>     {
>>         nTimesVarRead++;
>>         return internalValue;
>>     }
>>
>>     set { internalValue = $; }
>> }
>
> That defeats one of the purposes of properties. A property is usually an accessor for some member variable. You have two concepts: the property and the member variable; they MUST be declared separately, since they may have different attributes.
>
> For example, the underlying member variable may have any of public, protected or private visibility, while the property may also have any of public, protected or private visibility. Usually, the member variable is either protected or private, while the property is either public or protected.
>
> Also, the class itself, and any inner scopes, may want to access the underlying member variable directly, without going through the property accessors.
>

This proposal doesn't prevent any of that. Suppose our syntax was like in the example above. I would still be able to do something like this:

---------------
protected int _var;
public property char[] var
{
    // char[] internalValue is still defined,
    // but gets optimized away since it's never used.

    get { return ToString(_var); }
    set { _var = ToInt($); }
}
---------------

Also, we could say that the "internalValue" attribute of "private" (or protected, maybe we could have a way to optionally allow it to be protected) means "private to the class that contains the property" instead of "only accessible to the code within the property definition". Then we could do:

---------------
class Foo
{
    public property int myProp
    {
        get { return internalValue; }
        set { internalValue = $; }
    }

    public bar()
    {
        Stdout.formatln("{}", myProp.internalValue);
    }
}
---------------

Although I think I'm starting to really like the syntax being developed in another branch of this thread...(also I think I'm going to expand it a little):

---------------
module foo;
class Foo
{
    public property int myProp
    {
        get { return this; }
        set { this = this.new; }
    }

    // Shorthand for the same trivial accessors in "myProp"
    public property int myShorthandProp
    { get; set; }

    public property int readOnlyProp
    {
        get { return 7; }
    }

    public property int writeOnlyProp
    { set; }

    public property int polysemousProp
    {
        set { this = this.new; }
        get { return this; }

        set char[] { this = StringToInt(this.new); }

        // If we ever got overload-on-return-value
        get char[] { return IntToString(this); }
    }

    private property int privateProp
    { get; set; }

    public property int anotherProp
    {
        /* Change access attribute of internal value, default could be
either protected or private. This doesn't affect Foo's ability to see or not
see the internal value. This only affects Foo subclasses and code outside
the module. */
        protected this;

        get;

        // Foo can access anotherProp's setter, but everything else sees
anotherProp as read-only.
        private set;
    }

    public bar()
    {
        auto a = myProp; // Ok, uses getter
        auto b = myProp.this; // Ok, internal value
        auto c = privateProp; // Ok, uses getter
        auto d = privateProp.this; // Ok, internal value
        auto e = writeOnlyProp; // Error: no getter
        auto f = writeOnlyProp.this; // Ok, since we're inside Foo
    }
}

module main;
void main()
{
    auto foo = new Foo();

    auto a = myProp; // Ok, uses getter
    auto b = myProp.this; // Error: internal value is private to Foo
    auto c = privateProp; // Error: privateProp is private
    auto c = privateProp.this; // Error: privateProp is private
    auto e = writeOnlyProp; // Error: no getter
    auto f = writeOnlyProp.this; // Error: internal value is private to Foo
}
---------------

>> Perhaps, since the compiler knows the name of the property, the name of the generated internal value could just be the name of the property:
>>
>> public property int var
>> {
>>     get { return var; }
>>     set { var = $; }
>> }
>
> That is the question... the property is public, but var is private or protected? How does the class access var without triggering the property accessors?

See above.