February 05, 2013
On 02/04/2013 05:28 PM, Andrei Alexandrescu wrote:
> On 2/4/13 2:04 PM, Jonathan M Davis wrote:
>> We could save a lot of boilerplate code if we can simply make it
>> variables and
>> property functions guaranteed to be swappable without breaking code.
>
> I think this is quite powerful. The way we can do this is by making
> properties emulate a subset of actual variables.
>
> Andrei

I agree with Jonathan.

Please do not make them a subset.  Make them as identical as possible. The subset thing makes them no longer "swappable".  Allow variables to be marked with @property to limit them to operations that @property functions can do, and make sure @property functions are limited to what @property variables can do (ex: no address-of!).  With that in hand, they'll be very swappable.
February 05, 2013
On 2/4/13 10:30 PM, Chad Joan wrote:
> On 02/04/2013 05:28 PM, Andrei Alexandrescu wrote:
>> On 2/4/13 2:04 PM, Jonathan M Davis wrote:
>>> We could save a lot of boilerplate code if we can simply make it
>>> variables and
>>> property functions guaranteed to be swappable without breaking code.
>>
>> I think this is quite powerful. The way we can do this is by making
>> properties emulate a subset of actual variables.
>>
>> Andrei
>
> I agree with Jonathan.
>
> Please do not make them a subset. Make them as identical as possible.
> The subset thing makes them no longer "swappable". Allow variables to be
> marked with @property to limit them to operations that @property
> functions can do, and make sure @property functions are limited to what
> @property variables can do (ex: no address-of!). With that in hand,
> they'll be very swappable.

The purpose is to replace members with properties, not to change one's mind back and forth. There will be no marking of variables with @property as that can be easily achieved by actually making them properties.

Andrei
February 05, 2013
On 02/04/2013 11:18 PM, Andrei Alexandrescu wrote:
> On 2/4/13 10:30 PM, Chad Joan wrote:
>> On 02/04/2013 05:28 PM, Andrei Alexandrescu wrote:
>>> On 2/4/13 2:04 PM, Jonathan M Davis wrote:
>>>> We could save a lot of boilerplate code if we can simply make it
>>>> variables and
>>>> property functions guaranteed to be swappable without breaking code.
>>>
>>> I think this is quite powerful. The way we can do this is by making
>>> properties emulate a subset of actual variables.
>>>
>>> Andrei
>>
>> I agree with Jonathan.
>>
>> Please do not make them a subset. Make them as identical as possible.
>> The subset thing makes them no longer "swappable". Allow variables to be
>> marked with @property to limit them to operations that @property
>> functions can do, and make sure @property functions are limited to what
>> @property variables can do (ex: no address-of!). With that in hand,
>> they'll be very swappable.
>
> The purpose is to replace members with properties, not to change one's
> mind back and forth. There will be no marking of variables with
> @property as that can be easily achieved by actually making them
> properties.
>
> Andrei

Why not allow one to change their mind back and forth?

That would be far more useful from a design perspective.  With what you're proposing, there is no migration path for variables.  They are not swappable at all.  Once someone takes the address of your "public int foo;" it will no longer be possible to turn it into a property without breaking API.

Going even further, suppose we allow @property variables and also allow address-of on @property functions only (a subset relationship!).  Now it is possible to make a "public @property int foo;" that can be migrated to a full-fledged property later without some god-awful boilerplate. However, the developer will hesitate to make such a change: converting @property variables to @property functions is a liability.  Once you convert, you can't convert back without breaking API.  At that point the hypothetical developer wonders: "why am I using @property variables in the first place?  I can't migrate them because of the liability, which makes them no more useful than public variables that break encapsulation."  At that point the whole concept goes out the window and we're back in Java writing drivel like this:

class XYZ
{
  int m_foo;

  int getFoo()
  {
    return m_foo;
  }

  void setFoo(int val)
  {
    m_foo = val;
  }

  ...
}

I'm arguing the point because I'd much rather write this:

class XYZ
{
  @property int foo;
  ...
}
February 05, 2013
On Monday, February 04, 2013 23:18:57 Andrei Alexandrescu wrote:
> On 2/4/13 10:30 PM, Chad Joan wrote:
> > On 02/04/2013 05:28 PM, Andrei Alexandrescu wrote:
> >> On 2/4/13 2:04 PM, Jonathan M Davis wrote:
> >>> We could save a lot of boilerplate code if we can simply make it
> >>> variables and
> >>> property functions guaranteed to be swappable without breaking code.
> >> 
> >> I think this is quite powerful. The way we can do this is by making properties emulate a subset of actual variables.
> >> 
> >> Andrei
> > 
> > I agree with Jonathan.
> > 
> > Please do not make them a subset. Make them as identical as possible. The subset thing makes them no longer "swappable". Allow variables to be marked with @property to limit them to operations that @property functions can do, and make sure @property functions are limited to what @property variables can do (ex: no address-of!). With that in hand, they'll be very swappable.
> 
> The purpose is to replace members with properties, not to change one's
> mind back and forth. There will be no marking of variables with
> @property as that can be easily achieved by actually making them properties.

One of the main purposes generally given for having properties is so that you can make them public variables when you don't need them to do anything but get and set the member variable, but you can still make it a function later when you need to add other stuff to it (such as checking the value that it's being set to). One of the primary reasons for making a property function act like a variable is precisely so that you can switch between variables and functions when refactoring without breaking code.

Also, being able to mark variables as @property would save us a lot of boilerplate. Instead, it's incredibly common to do stuff like

struct S
{
    @property int prop() @safe const pure nothrow
    { return _prop; }

    @property int prop(int value) @safe pure
    { return _prop =  value; }

    private int _prop;
}

That's a lot of extra code just to buy some encapsulation. If we could do

struct S
{
    @property int prop;
}

we could really reduce the amount of boilerplate code surrounding member variables. Even if putting @property on a variable simply lowered to the property functions rather than it still be a variable, it would be a big help. But without either that or marking variables with @property so that you can't do anything to them that you can't do to a property function, we lose the ability to make a property a variable when the getters and setters are unnecessary, and that means that we're stuck with a lot of extra boilerplate.

- Jonathan M Davis
February 05, 2013
On 02/04/2013 11:18 PM, Andrei Alexandrescu wrote:
> On 2/4/13 10:30 PM, Chad Joan wrote:
>>
>> I agree with Jonathan.
>>
>> Please do not make them a subset. Make them as identical as possible.
>> The subset thing makes them no longer "swappable". Allow variables to be
>> marked with @property to limit them to operations that @property
>> functions can do, and make sure @property functions are limited to what
>> @property variables can do (ex: no address-of!). With that in hand,
>> they'll be very swappable.
>
> The purpose is to replace members with properties, not to change one's
> mind back and forth. There will be no marking of variables with
> @property as that can be easily achieved by actually making them
> properties.
>
> Andrei

Related:
Is there some reason why we /need/ to be able to take the address of properties?

Wouldn't something like 'someFunc(PropAccessor!"prop"(foo))' work in cases where we need a generic way to defer reads and writes?

For clarity:

auto PropAccessor(string propertyStr, T)( T tinstance )
{
    struct Accessor(string propertyStr, U)
    {
        private U tinstance;

        auto get()
        {
            mixin("return tinstance."~propertyStr~";");
        }

        // I had to put @system here to shut up a compiler error.  Bug?
        @system void set(V)(V val)
        {
            mixin("tinstance."~propertyStr~" = val;");
        }
    }

    Accessor!(propertyStr, T) acc;
    acc.tinstance = tinstance;
    return acc;
}

auto PtrAccessor(T)( T* payload )
{
    struct Accessor(U)
    {
        private U* payload;

        U get()
        {
            return *payload;
        }

        U set(U val)
        {
            return *payload = val;
        }
    }

    Accessor!(T) acc;
    acc.payload = payload;
    return acc;
}

template isAccessor(Acc)
{
    Acc a;
    static if (
        __traits(compiles, { auto x = a.get(); } ) &&
        __traits(compiles, a.set(a.get())) )
        const bool isAccessor = true;
    else
        const bool isAccessor = false;
}

// Function that accepts the be-all-end-all of reference types.
auto someFunc(Acc)(Acc qux) if ( isAccessor!(Acc) )
{
    auto x = qux.get();
    x |= 0xF00D;
    qux.set(x);
    return qux.get();
}

struct MyStruct
{
    private int m_q;
    @property int q() { return m_q; }
    @property void q(int v) { m_q = v; }
}

unittest
{
    MyStruct s;
    s.q = 0;
    int abc = 0;
    assert(someFunc(PtrAccessor(&abc)) == 0xF00D);
    assert(someFunc(PropAccessor!"q"(s)) == 0xF00D);
}

void main()
{
}
February 05, 2013
On 2013-02-04 23:52, Jonathan M Davis wrote:

> Which is why I would argue that we need to be able to mark variables with
> @property (which either makes it so that you can't do anything with them that
> you can't do with a property function or makes it so that it lowers to
> property functions for getting and setting), and we need to disallow taking
> the address of property functions as well as anything else that you could do
> with a variable that we can't emulate with a property function.

They need to be lowered to methods. Otherwise you cannot switch from a method to a field, since methods are virtual and can be overridden in unknown subclasses.

-- 
/Jacob Carlborg
February 05, 2013
On 2013-02-05 05:18, Andrei Alexandrescu wrote:

> The purpose is to replace members with properties, not to change one's
> mind back and forth. There will be no marking of variables with
> @property as that can be easily achieved by actually making them
> properties.

Why not? That will just require needless boilerplate code, wrappers just forwarding to instance variables.

I have wanted to have this since the introduction of the @property keyword.

-- 
/Jacob Carlborg
February 05, 2013
On 2013-02-05 07:13, Jonathan M Davis wrote:

> One of the main purposes generally given for having properties is so that you
> can make them public variables when you don't need them to do anything but get
> and set the member variable, but you can still make it a function later when
> you need to add other stuff to it (such as checking the value that it's being
> set to). One of the primary reasons for making a property function act like a
> variable is precisely so that you can switch between variables and functions
> when refactoring without breaking code.
>
> Also, being able to mark variables as @property would save us a lot of
> boilerplate. Instead, it's incredibly common to do stuff like
>
> struct S
> {
>      @property int prop() @safe const pure nothrow
>      { return _prop; }
>
>      @property int prop(int value) @safe pure
>      { return _prop =  value; }
>
>      private int _prop;
> }
>
> That's a lot of extra code just to buy some encapsulation. If we could do
>
> struct S
> {
>      @property int prop;
> }
>
> we could really reduce the amount of boilerplate code surrounding member
> variables. Even if putting @property on a variable simply lowered to the
> property functions rather than it still be a variable, it would be a big help.
> But without either that or marking variables with @property so that you can't
> do anything to them that you can't do to a property function, we lose the
> ability to make a property a variable when the getters and setters are
> unnecessary, and that means that we're stuck with a lot of extra boilerplate.

I fully agree. But they do need to be lowered to methods, see:

http://forum.dlang.org/thread/kel6c8$1h5d$1@digitalmars.com?page=17#post-keqfol:242un9:241:40digitalmars.com

-- 
/Jacob Carlborg
February 05, 2013
On 2013-02-05 07:13, Jonathan M Davis wrote:

> One of the main purposes generally given for having properties is so that you
> can make them public variables when you don't need them to do anything but get
> and set the member variable, but you can still make it a function later when
> you need to add other stuff to it (such as checking the value that it's being
> set to). One of the primary reasons for making a property function act like a
> variable is precisely so that you can switch between variables and functions
> when refactoring without breaking code.
>
> Also, being able to mark variables as @property would save us a lot of
> boilerplate. Instead, it's incredibly common to do stuff like
>
> struct S
> {
>      @property int prop() @safe const pure nothrow
>      { return _prop; }
>
>      @property int prop(int value) @safe pure
>      { return _prop =  value; }
>
>      private int _prop;
> }
>
> That's a lot of extra code just to buy some encapsulation. If we could do
>
> struct S
> {
>      @property int prop;
> }
>
> we could really reduce the amount of boilerplate code surrounding member
> variables. Even if putting @property on a variable simply lowered to the
> property functions rather than it still be a variable, it would be a big help.
> But without either that or marking variables with @property so that you can't
> do anything to them that you can't do to a property function, we lose the
> ability to make a property a variable when the getters and setters are
> unnecessary, and that means that we're stuck with a lot of extra boilerplate.

BTW, if it does get lowered to methods, do we want to be able to access the instance variable directly? I think it's good to be able to bypass the setter/getter sometimes internally. Alternatively there could be a __traits to access the instance variable.

-- 
/Jacob Carlborg
February 05, 2013
On 02/05/2013 02:28 AM, Andrei Alexandrescu wrote:> On 2/4/13 2:04 PM, Jonathan M Davis wrote:
>> We could save a lot of boilerplate code if we can simply make it
>> variables and
>> property functions guaranteed to be swappable without breaking code.
>
> I think this is quite powerful. The way we can do this is by making
> properties emulate a subset of actual variables.
>

This is the primary real-world proble to solve.
If tackle it right  we'd secure a sizable flow of Java
converts simply because of this feature alone ;)

More seriously I believe it's worth noting that properties can't emulate (in principle) exactly one aspect of variable - taking address
as a pointer. Honestly I can't see a way to overcome it without introducing a user-defined way to impose this restriction on a field of a struct/class.

Then keeping in mind __traits I have the following clause to add to the current proposal:

Inside of aggregate a field marked with @property indicate is semantically equivalent to compiler wrapping it with trivial getter and setter. Example:
struct Foo{
@property T x;
}

treated  semantically as if:
T __x; // hidden by compiler
//templated to have deduced safe, pure, nothrow
@property T x()()inout{ return x; }
@property void x()(T val){ x = val; }



---
Dmitry Olshansky