ref returns and properties
Steven Schveighoffer
schveiguy at yahoo.com
Mon Jan 26 18:34:09 PST 2009
"Denis Koroskin" wrote
> On Tue, 27 Jan 2009 01:52:26 +0300, Steven Schveighoffer
> <schveiguy at yahoo.com> wrote:
>
>> "Andrei Alexandrescu" wrote
>>> Steven Schveighoffer wrote:
>>>> I guess I'm not really sure what the "acquire" method does. I saw you
>>>> mention it in another post, but with no explanation as to what it
>>>> actually does, just that it was needed. I'm sure I'm not getting what
>>>> should be obvious, but if you could enlighten, I would appreciate it :)
>>>
>>> Say you have an object obj that has a Matrix property and you have a
>>> Matrix object handy. The Matrix is rather resource intensive so you'd
>>> rather not copy it unwittingly. Conventionally, if you say:
>>>
>>> Matrix m;
>>> ... fill matrix ...
>>> obj.matrix = m;
>>>
>>> then m is copied into obj.matrix (there is the by-value call to set
>>> property). Now it's possible to arrange things such that m is
>>> destructively copied, but as the auto_ptr disaster has shown, it's not
>>> that intuitive to make assignment destroy the right hand side.
>>>
>>> So we'd need a distinct method:
>>>
>>> obj.matrix.acquire(m);
>>>
>>> That method takes the matrix by reference, sucks its life out of it, and
>>> leaves an empty shell behind. Pretty much like in your average horror
>>> movie.
>>
>> So what you are saying is that you want to control the set such that it
>> destroys the source (essentially, I'm reading, you don't want to do a
>> deep
>> copy, just a reference copy, and then null the original reference).
>>
>> Let me ask another question then... does a property have reason to have
>> both
>> set AND acquire? More specifically, does a function that takes a
>> property
>> as an argument as we have been discussing need both set and acquire
>> passed
>> to it? If not, you can simply pass the set method that you want, still
>> only
>> requiring a pair of functions. How to signal that to the compiler
>> easily?
>> Not so sure... but it does seem to me like a type should know how it
>> should
>> be copied, and likely doing it other ways should require special methods.
>>
>> I can think of possible library solutions to this, say a wrapper property
>> struct that can call any two functions to do set or get.
>>
>>>
>>>> Having the two functions seems like a reasonable baggage compromise, if
>>>> you want to control the get and set methods of a property and pass that
>>>> control to an underlying function, you need at least that. If we start
>>>> generalizing it to anything, then it starts looking like struct
>>>> interfaces would be more suitable. For example, you could allow
>>>> setting
>>>> an int property using both an int and a string, do you want to pass
>>>> both
>>>> setters to a function? I think limiting it to just a set and a get
>>>> function should be sufficient.
>>>
>>> With only get and set I can't implement a nothrow swap, which kinda
>>> bends
>>> me out of shape.
>>
>> Sorry, don't get that either. Why can't set and get be used in a nothrow
>> swap?
>>
>> -Steve
>>
>>
>
> Because set implies data copying (read: allocation) and copy constructor
> call, both of which can throw.
>
> How about the following - you call a swap with a dot syntax:
>
> int x = 42;
> int y = 13;
>
> x.swap(y); // calls global void swap(T)(ref T, ref T); or a specialized
> version, swap(ref int, ref int);
>
> User is, however, free to implement his own swap method:
>
> struct BigInt
> {
> ...
> void swap(ref BigInt other) { ... }
> ...
> }
>
> Or another way - "void swap(T)(ref T lhs, ref T rhs);" tries
> "lhs.swap(rhs);" first, and falls back to "auto tmp = lhs; lhs = rhs; rhs
> = tmp;" if no lhs.swap method is defined.
> This way you can define "void aquire(ref T newOwner, ref T data);" as
> "newOwner.aquire(data);" and fall back to "swap(newOwner, data);
> release(data);" on failure.
> "void release(ref T obj);" tries "obj.release();" first and falls back to
> "swap(obj, T());" or "obj = T();" on failure.
OK, I think I got what you and Andrei are saying. I had to think about this
a while, and I think Denis is right. Leave the swap implementation up to
the type, not the holder of the type. A property should be a simple
interface to define how to access an object's data, which is the most common
case. Putting in all these extra methods and features to allow the
possibility of a non-specific swap function for certain uncommon cases seems
like you are trying to remove complexity from an opaque low level function
and adding the complexity to all properties in existance instead. i.e. if
you want to sort an array of matrices which are expensive to make copies of,
then you need a special swap, you can't use the generic one, because it's
not a generic swap. Let the type tell you how to do it or let the developer
pass in a swap function. Don't put the intelligence into the holder of the
type(which in this case would be a range). For simple types, a complex swap
or property interface isn't necessary.
I hope that was clear, it's hard to express what I'm trying to say...
-Steve
More information about the Digitalmars-d
mailing list