Using ()s in @property functions

Robert Jacques sandford at jhu.edu
Tue Jun 29 22:10:43 PDT 2010


On Wed, 30 Jun 2010 01:00:53 -0400, Chad J  
<chadjoan at __spam.is.bad__gmail.com> wrote:

> On 06/30/2010 12:33 AM, Robert Jacques wrote:
>> On Tue, 29 Jun 2010 23:41:48 -0400, Andrei Alexandrescu
>> <SeeWebsiteForEmail at erdani.org> wrote:
>> .
>>> Robert Jacques wrote:
>>>> On Tue, 29 Jun 2010 11:44:07 -0400, Andrei Alexandrescu
>>>> <SeeWebsiteForEmail at erdani.org> wrote:
>>>>
>>>>> Steven Schveighoffer wrote:
>>>>>> On Tue, 29 Jun 2010 10:15:10 -0400, Leandro Lucarella
>>>>>> <luca at llucax.com.ar> wrote:
>>>>>>
>>>>>>> Steven Schveighoffer, el 29 de junio a las 08:13 me escribiste:
>>>>>>>> >>There is one thing that bugs me about this solution though.
>>>>>>>> What if the
>>>>>>>> >>user does this:
>>>>>>>> >>(1) Grab the pointer.  *ptr = prop;
>>>>>>>> >(1) Grab the pointer.  T* ptr = &prop;
>>>>>>>> >
>>>>>>>> >>(2) assigns to it.  *ptr = val;
>>>>>>>> >>(3) expects the result to be updated in prop.  assert(val ==
>>>>>>>> prop);
>>>>>>>> >
>>>>>>>>
>>>>>>>> Why would this assert fail?  If a property returns a ref
>>>>>>>
>>>>>>> What if it doesn't? If returns a temporary calculated value?
>>>>>>  It returns a ref.  That can't be a calculated value.  If it's a
>>>>>> calculated value then T* ptr = &prop will fail to compile.
>>>>>
>>>>> It's a "calculated reference", e.g. several instances could share
>>>>> the same value etc. Once the reference is out, clearly there's no
>>>>> more control.
>>>>>
>>>>> I agree with the view that a @property returning ref should be
>>>>> virtually indistinguishable from a field. Currently that's not the
>>>>> case, e.g. if you want to assign to such a property you must add
>>>>> parens:
>>>>>
>>>>> struct A { int x; @property ref y() { return x; } }
>>>>>
>>>>> unittest
>>>>> {
>>>>>      A a;
>>>>>      a.y = 5; // fails
>>>>>      a.y() = 5; // works
>>>>> }
>>>>>
>>>>>
>>>>> Andrei
>>>>  Okay, but what about non-ref properties? i.e.
>>>>  struct A {
>>>>    int x;
>>>>    @property int y()      { return x; }
>>>>    @property int y(int v) { return x = v; }
>>>> }
>>>>  unittest {
>>>>    A a;
>>>>    int* ptr = &a.x; // works
>>>>    int* ptr = &a.y; // fails
>>>> }
>>>>  Is there a good way of patching this leak in the @property  
>>>> abstraction?
>>>
>>> I don't think you should be able to even take the address of a non-ref
>>> property.
>>>
>>> Andrei
>>
>> I agree with you from a under-the-hood perspective, but I wasn't asking
>> about that. I was asking about the leak in the @property abstraction.
>> Not being able to pass non-ref @properties to functions by ref is a
>> fairly serious (i.e. common) break/leak in the @property abstraction:
>> that @properties should be "virtually indistinguishable from a field".
>
> ref parameters are easily handled by property expression rewriting:
>
> void foo( ref bar ) { ... }
>
> foo(prop)
>
> becomes
>
> auto t = prop()
> foo(t)
> prop(t)
>
> I would handle "out" parameters similarly, but without calling the
> getter.  They are essentially a different way of writing an assignment.
>
> Taking the /address/ is a bit different, since there may be no
> well-defined line of code at which the pointer holding the address dies.
>  The ref parameter, on the other hand, WILL expire when the function
> returns.

Nope. That's a data race. Consider the case where foo has access to prop's  
object. Essentially, t is stale, so this breaks the concept of reference  
semantics.


More information about the Digitalmars-d mailing list