On Tue, 05 May 2015 11:54:53 -0400, Jonathan M Davis <jmdavisp...@gmx.com>
wrote:
On Tuesday, 5 May 2015 at 02:47:03 UTC, bitwise wrote:
On Mon, 04 May 2015 00:16:03 -0400, Jonathan M Davis via
Digitalmars-d-learn <digitalmars-d-learn@puremagic.com> wrote:
D will move the argument if it can rather than copying it (e.g. if a
temporary is being passed in), which reduces the need for worrying
about
copying like you tend to have to do in C++98, and I think that a lot
of D
code just doesn't worry about the cost of copying structs.
How exactly would you move a struct? Just a memcpy without the postblit?
Because D has postblit constructors rather than copy constructors,
copying is done by blitting the entire struct and then calling the
postlblit constructor afterwards, so unless the postlbit constructor is
@disabled, a struct is moveable simply by blitting it and not calling
the postblit constructor afterwards. And the compiler can choose to do a
move whenever a copy is unnecessary (e.g. return value optimization or
when a temporary is passed to a
Gotcha.
Correct me if I'm wrong though, but in C++(and I don't see why D would be
different), RVO removes the need for the struct/class to be blitted
completely. The struct/class will simply be constructed directly to the
return address to begin with.
I don't see how the above could achieved with parameter passing(by value),
which is why I suggest rvref.
Something like a Matrix4x4 lives in an awkward place between a class
and a struct. Because of the fact that a graphics engine may have to
deal with thousands of them per frame, both copying them at function
calls, and allocating/collecting thousands of them per frame, are both
unacceptable.
I was reading up(DIP36, pull requests, forum) and it seems like auto
ref was supposed to do something like this. Is there a reason you
didn't mention it?
You could use auto ref, but then you'd have to templatize the function,
since it only works with templated functions, and if you have multiple
auto ref parameters, then you'll get a combinatorial explosion of
template instantations as you call the function with different
combinations of lvalues and rvalues. It's basically like declaring each
of the combinations of the function with ref and non-ref parameters, but
you don't have to declare them all, and it doesn't work with virtual
functions. I didn't mention auto ref mostly just to be simple.
But because of that combinatorial explosion (be they declared implicitly
via auto ref or manually) is a good reason IMHO to just not worry about
this problem in most cases. It's just too tedious to duplicate all
functions like that, and using templates isn't always acceptable.
In theory, auto ref could work for non-templated functions by making it
so that underneath the hood as ref except that any time you passed it an
rvalue, it implicitly defined an lvalue for you to pass to the function,
but that doesn't match what happens with auto ref with non-templated
functions, and changing the behavior for templated functions would be
unacceptable, because it would reduce our ability to forward parameters
without changing their type, so we'd end up with auto ref doing
different things on templated and non-templated functions, which is
potentially confusing. And that solution has simply never been agreed
upon. I have no idea if it ever will be.
I'm not really worried about the symbol explosion, because most of the
functions I would be using would be binary at most. I'm more worried about
losing the ability to use virtual/non-templated functions with
lvalue+rvalue refs.
I really do believe this should be fixed. D SHOULD have a way to pass a
large struct parameter as a ref whether its an lvalue or an rvalue without
copying. And when I say copying, this includes blitting without calling
postblit, which would still be quite pricey for something like a
Matrix4x4(64 bytes for floats) if it had to happen thousands of times per
frame in real time. And trading these thousands of copies for
allocations/collections is just as bad.
Why not just add "rvref" to D?
Because we have too many attributes already. It's actually kind of
astonishing that we're getting return ref, because Andrei was adamant
that we not add any more parameter attributes, because we simply have
too many already. I think that the only reasons that return ref is
making it in is because of how it solves a real need and how simple it
is, whereas Andrei is not at all convinced that having anything like
C++'s const& in D is needed. And while it might be nice, for the most
part, we _are_ able to mostly write code without worrying about it.
I do understand this, but what's more astonishing is that things have
gotten this far and there isn't as way to pass a struct without making
unnecessary copies ;)
In a practical sense, I suppose templates/auto ref will mitigate the
problem _well_enough_ for now, but it's an hack that only works with
templates and my code will still be creating copies all over the place for
no reason.
Bit