On Saturday, 13 February 2016 at 17:47:54 UTC, Lars T. Kyllingstad wrote:
Not knowing anything about the libraries you write, it's hard to argue with that. But I agree that given that you are in control of all the code AND can make the move ctor/assignment available for inlining (AND are an experienced programmer),

C++ does indeed put the burden on the library programmer and is not a good language for "non-professional" use. But it is flexible by providing the mechanisms in the type system rather than an opinionated solution. (Of course, parts of the C++ standard library is opinionated.)

cannot be inlined. Then, you are looking at multiple levels of function calls and you are also at the mercy of whoever wrote their move code.

Well, I primarily use move semantics for ownership, like owning resources in the GPU, files system, memory etc. So it usually is 1 or 2 levels.


Here, you have unnecessary construction of C's members in the constructor which may or may not be optimised away before the assignment.

Well, doing a swap would break the expectations for assignment...

Furthermore, you have an unnecessary number of moves in the assignment operator -- plus the potential drawbacks of deferred release of the resource.

I don't understand what you mean by unnecessary moves? std::move/std::forward are just type casting so they don't result in code...

I'm not sure what you mean by "has move semantics" here. It does not have C++'s move semantics, no, but I would say D has its own move semantics. It has a move() function that transfers raw state between objects, and D structs are supposed to be designed so they are movable by means of raw bit transfer, allowing the compiler and GC to move them around as it sees fit. But maybe I'm missing something?

Well, but that is like saying that C++03 also had move semantics. There is nothing special about D's move(), it's just a library function?

No? With D's std.move() the resource can be destroyed or get into an inconsistent state if the caller does it wrong?

I guess this is what I don't understand. How and when does that happen?

The std.move() actually does a copy, then copy the init value to the original. If something happens that prevents the value from being preserved the object will be destroyed by the destructors. I.e. an exception.

And worse, if you have back pointers to it, it will end up being inconsistent. There is no way the type system can prevent back pointers without preventing D from being usable as a language. Since you no longer have the original object... shit can happen. In C++ you can set a mutex in the object and fix things because you have the full object. So if someone tries to follow the back pointer the mutex will block. You can probably come up with many other scenarios. "postblit" does not fix this (not a very elegant solution IMO).

So, C++ gives the library author control by having "move" be part of the type system that essentially does nothing else than applying some constraints. Having "move" as an action is both limiting and potentially flawed, since the D compiler does not do anything to ensure correctness. If "move" is an action, rather than a type system constraint, then it should be backed up with semantic analysis IMO.

Reply via email to