View mode: basic / threaded / horizontal-split · Log in · Help
May 03, 2012
How to modify an element in a range/collection using its member function?
Hi,

in Phobos opIndex returns a copy due to the reasons outlined in TDPL p.
378 (hiding the storage). Even though I find the argumentation
convincing and opIndexAssign/opIndexOpAssign usually makes the design
sound I ran into surprises when using member functions.
I use the Zip the range which has the same behavior, i.e. return a copy.
Consider a random-access range/container R of say 10 points.

auto c = R!Point(10);

If Point has member functions you naturally write buggy code as I did
(operating on a temporary Point).
c[2].changePointSomehow();

The work around is
auto tmp = c[2];
tmp.changePointSomehow();
c[2] = tmp;
which does not look good to me. Simply things should be simple.
swap won't work as changePointSomehow() does not return the modified
Point.

Should std.range.Zip be an exception and return by reference? Because it
actually does not store anything. I don't like this as Zip may perform
some optimization for indexing.

What is a good solution when using member functions on a
range's/container's element?

Note, the problem only applies when storing structs because classes
behave like references.

Jens
May 03, 2012
Re: How to modify an element in a range/collection using its member function?
I don't think that opIndexAssign/opIndexOpAssign were ever a good 
idea. Yeah, it works fine when all you are doing is x[i] = y, but 
that doesn't scale, as you have found out. It's short-sighted.

x[i] is an L-value for arrays, so it should be for everything 
else where it makes sense. Consistency is paramount.

I know C++ had the problem with std::map where x[i] would 
construct an entry when x[i] didn't exist, but that was due to a 
bad design decision. Indexing should never perform an insertion. 
Force users to use an 'insert' function to add elements and 
indexing should only work when the key is found (throw an 
exception otherwise). Again, it's a matter of consistency. 
Accessing x[10] of a 5-element array doesn't expand the array, so 
accessing x["foo"] of an empty map shouldn't expand the map.

Am I missing something here?
May 03, 2012
Re: How to modify an element in a range/collection using its member function?
On Thursday, 3 May 2012 at 10:03:55 UTC, Jens Mueller wrote:
> What is a good solution when using member functions on a
> range's/container's element?
>
> Note, the problem only applies when storing structs because 
> classes
> behave like references.

I think in this case, it might make sense to store pointers to 
structs.

So,

auto c = R!(Point*)(10);

OR

alias Point* PointRef;
auto c = R!PointRef(10);


Let me know if there's something wrong with this approach.
May 04, 2012
Re: How to modify an element in a range/collection using its member function?
Chris Cain wrote:
> On Thursday, 3 May 2012 at 10:03:55 UTC, Jens Mueller wrote:
> >What is a good solution when using member functions on a
> >range's/container's element?
> >
> >Note, the problem only applies when storing structs because
> >classes
> >behave like references.
> 
> I think in this case, it might make sense to store pointers to
> structs.
> 
> So,
> 
> auto c = R!(Point*)(10);
> 
> OR
> 
> alias Point* PointRef;
> auto c = R!PointRef(10);
> 
> 
> Let me know if there's something wrong with this approach.

Assume you are using Phobos which returns a range as ranges are the
glue keeping Phobos together and leading to a coherent interface. Then
there is no way to get a pointer or similar. Your solution does work in
cases when I control the storage but that should be rare cases.
Additionally using pointers clutters the code I think.

In essence: Whenever you are using a range of some struct in Phobos then
calling a mutating member function on its elements won't do what you are
expecting. You have to resort to copying/moving. I.e. a range's element
can only be changed by copying/moving.

I wonder how often other Phobos users run into this issue. Only Peter
finds this issue to be problematic. When we have ranges everywhere the
result may be much more troublesome.

Thanks for your reply.

Jens
Top | Discussion index | About this forum | D home