March 15, 2021
On Monday, 15 March 2021 at 05:45:01 UTC, Walter Bright wrote:
> On 3/11/2021 5:40 PM, tsbockman wrote:
>> Is this correct?
>
> The idea of the move constructor is the user takes over the task of doing whatever it takes to make it work, i.e. handle the destruction.

That's not what I was asking about. I understand what a move *constructor* does.

Rather, I was trying to figure out, "How can your definition of move *assignment* be represented in code?" You tried to answer this, my actual question, earlier, but your answer was just as vague as the DIP:

From the DIP:
> After the move is complete, the destructor is called on the
> original contents of the constructed object.

Since the move overwrites the original contents, it's not immediately obvious how the destructor can be called on those original contents, which are gone, *after* the move.

On Thursday, 11 March 2021 at 08:36:18 UTC, Walter Bright wrote:
> The idea is that the move assignment operation takes care of
> this, and makes it "as if" the move was done, then the
> destruction.

If the algorithm is unclear or missing steps, saying, "You don't actually have to do it, you just have to do something equivalent," doesn't help. A clear, complete, and logically valid algorithm needs to be defined *first*, to determine whether another algorithm is equivalent.

I was trying to figure out what your original, general-purpose move *assignment* algorithm could be. That's what my code example is for.

I found a candidate that seems to work, and to fit your description (`this` and `source` are both passed in by reference):

0) Move-construct the `source` into a temporary `newValue`.
1) Clear `source` in such a way that destroying its value would be a no-op.
2) Move-construct the original value of the destination `this` into a temporary `oldValue`.
3) Move-construct `newValue` into the destination `this`.
4) Destroy `oldValue`.

This is complicated, but everything simpler I tried either doesn't match your description, or doesn't pass my tests. Runnable example:
    https://gist.github.com/run-dlang/b789714c01905f091a44ee2666276433

Is this correct?
March 16, 2021
On 3/15/2021 1:09 PM, tsbockman wrote:
> I was trying to figure out what your original, general-purpose move *assignment* algorithm could be. That's what my code example is for.

The answer is, it depends on how the programmer set up the contents of the object, in particular, how the ownership works. It's up to the programmer to make it work so the user of the type sees the semantics as described.

For example, if it's pointing to unique objects, then the destructor for the destination is called first. If it's pointing to ref counted objects, then the destructor is called last.

The language doesn't specify that. The programmer does, and the programmer needs to make it work. Hence the "as if" rule.
March 16, 2021
On 3/15/2021 10:18 AM, H. S. Teoh wrote:
> I'm sure Walter would have made alias this illegal in classes a long
> time ago, if it were possible without problems.  I'm suspecting the
> "don't break existing code" bugbear is among the reasons.

Right.

> I used to be a big fan of alias this, esp. multiple alias this.  Now,
> after some experience with maintaining code that use alias this
> willy-nilly, I'm starting to agree with Walter's stance that alias this
> in general was a bad idea.  Although there are definitely cases for
> which it's actually useful, the problems it brings along make it of
> questionable value as a general language feature.  I'd also be in favor
> of getting rid of it, at least from classes, if not completely. (The
> latter is probably impossible; quite a lot of my own code relies on it,
> and I imagine I'm not the only one using it among the users of D.)

Right, we're kinda stuck with it. But move constructors are a new thing, and ignoring interaction with class alias thing will not break existing code. If someone wants to use move constructors, don't mix them with class alias this.

Alias this should only be used with structs, and modestly at that. Being clever with it will only annoy the dragon :-/
March 16, 2021
On 3/12/2021 4:29 AM, deadalnix wrote:
> On Friday, 12 March 2021 at 02:06:19 UTC, Walter Bright wrote:
>> On 3/11/2021 4:57 PM, deadalnix wrote:
>>> These problems seems to arise due to the fact postblit did not distinguish between move and copy.
>>>
>>> postblit is inappropriate for copy, but as far as I can tell, not only does it work for move, but it's the only path that do not involve creating yet more magic that's going to bite us in the ass at some point.
>>
>> postblit bit us in the ass quite a bit. (postblit didn't do moves)
> 
> You are making my point, yet for some reason miss it anyways.
> 
> Postblit works with *1* object. It fails at being a good copy mechanism because copying involves *2* objects, by definition.
> 
> Move works with *1* object. opAssign will, similarly to what happened when using postblit for copies, lead to problems because it inherently works with *2* objects.

Postblit's problems arose from it not having access to both objects. The opAssign does have access to both, and the qualifiers can be applied to both parameters, so I don't see a barrier to it working.


> Postblit is a natural fit for moves because both work with *1* object, thus not leaving an object out there is some sort of magic state that we can never figure out what to do with.
> 
> There is already a fair bit of magic that is proposed to be added to opAssign in this proposal, yet it is now obvious to me that there are already holes in it. For instance, if one of the fields of the object ends up not being moved, how will this fields ends up being destroyed? How is that even fixable considering the whole thing can be n-levels deep? The only way I this being fixed is be reintroducing the notion that structs must have a null state and destroy the object anyways post move, but going there would be a big optimization barrier, while not going there creates a situation where things that should be destroyed ends up not being, which is also pretty bad.
> 
> On the other hand, the postblit by its very nature does not allow for this whole situation to arise to begin with. If a field is not going to be moved, it will have to see some new value assigned there, causing the destruction of the old value.

An opAssign gives the implementer complete control over the operation of it, including when and how destruction takes place of the original destination's contents.
March 16, 2021
On Tuesday, 16 March 2021 at 08:27:27 UTC, Walter Bright wrote:
> On 3/15/2021 10:18 AM, H. S. Teoh wrote:
>> I'm sure Walter would have made alias this illegal in classes a long
>> time ago, if it were possible without problems.  I'm suspecting the
>> "don't break existing code" bugbear is among the reasons.
>
> Right.
>
>> I used to be a big fan of alias this, esp. multiple alias this.  Now,
>> after some experience with maintaining code that use alias this
>> willy-nilly, I'm starting to agree with Walter's stance that alias this
>> in general was a bad idea.  Although there are definitely cases for
>> which it's actually useful, the problems it brings along make it of
>> questionable value as a general language feature.  I'd also be in favor
>> of getting rid of it, at least from classes, if not completely. (The
>> latter is probably impossible; quite a lot of my own code relies on it,
>> and I imagine I'm not the only one using it among the users of D.)
>
> Right, we're kinda stuck with it. But move constructors are a new thing, and ignoring interaction with class alias thing will not break existing code. If someone wants to use move constructors, don't mix them with class alias this.
>
> Alias this should only be used with structs, and modestly at that. Being clever with it will only annoy the dragon :-/

Here is my suggestion, deprecate alias this for classes, but the date for the removal of them to be never. With the ability to silence the deprecation if needed. There done. Simple. It won't break old code, but it will discourage new bad code from being created.

-Alex
March 16, 2021
On Monday, 15 March 2021 at 17:18:19 UTC, H. S. Teoh wrote:

> Although there are definitely cases for which it's actually useful, the problems it brings along make it of questionable value as a general language feature.  I'd also be in favor of getting rid of it, at least from classes, if not completely. (The latter is probably impossible; quite a lot of my own code relies on it, and I imagine I'm not the only one using it among the users of D.)

A feature that can't be used wrong isn't much of a feature. alias this is easy to use correctly and provides immense value. The removal of useful features is not a good solution to bad program design.
March 16, 2021
On Tue, Mar 16, 2021 at 03:18:49PM +0000, bachmeier via Digitalmars-d wrote:
> On Monday, 15 March 2021 at 17:18:19 UTC, H. S. Teoh wrote:
> 
> > Although there are definitely cases for which it's actually useful, the problems it brings along make it of questionable value as a general language feature.  I'd also be in favor of getting rid of it, at least from classes, if not completely. (The latter is probably impossible; quite a lot of my own code relies on it, and I imagine I'm not the only one using it among the users of D.)
> 
> A feature that can't be used wrong isn't much of a feature. alias this is easy to use correctly and provides immense value. The removal of useful features is not a good solution to bad program design.

I used to have your stance.  But these days, I'm starting to realize more and more that implicit conversions are almost always a bad idea. They are convenient and fast in the beginning when you're trying to get the job done, but in the long term, they hurt readability and maintainability.  I've come to realize that when the code relies too much on this kind of implicit conversion, esp. via alias this, it's often a sign of poor code structure. It's a code smell.  It works, but smells bad, and eventually you realize that it *is* bad.


T

-- 
Talk is cheap. Whining is actually free. -- Lars Wirzenius
March 16, 2021
On Tuesday, 16 March 2021 at 16:08:46 UTC, H. S. Teoh wrote:
> On Tue, Mar 16, 2021 at 03:18:49PM +0000, bachmeier via Digitalmars-d wrote:
>> On Monday, 15 March 2021 at 17:18:19 UTC, H. S. Teoh wrote:
>> 
>> > Although there are definitely cases for which it's actually useful, the problems it brings along make it of questionable value as a general language feature.  I'd also be in favor of getting rid of it, at least from classes, if not completely. (The latter is probably impossible; quite a lot of my own code relies on it, and I imagine I'm not the only one using it among the users of D.)
>> 
>> A feature that can't be used wrong isn't much of a feature. alias this is easy to use correctly and provides immense value. The removal of useful features is not a good solution to bad program design.
>
> I used to have your stance.  But these days, I'm starting to realize more and more that implicit conversions are almost always a bad idea. They are convenient and fast in the beginning when you're trying to get the job done, but in the long term, they hurt readability and maintainability.  I've come to realize that when the code relies too much on this kind of implicit conversion, esp. via alias this, it's often a sign of poor code structure. It's a code smell.  It works, but smells bad, and eventually you realize that it *is* bad.

If you're calling into a C library for matrix operations, but you have three or more strategies for allocating the underlying memory, alias this is reasonable. Otherwise you're writing *extremely* verbose code or you need to engage in extraordinary code duplication or you're writing a bunch of ugly generic code that sits on top of the C library. alias this is a clean, trivial solution in this case.

March 16, 2021
On Tuesday, 16 March 2021 at 16:55:47 UTC, bachmeier wrote:
> [snip]
>
> If you're calling into a C library for matrix operations, but you have three or more strategies for allocating the underlying memory, alias this is reasonable. Otherwise you're writing *extremely* verbose code or you need to engage in extraordinary code duplication or you're writing a bunch of ugly generic code that sits on top of the C library. alias this is a clean, trivial solution in this case.

Generic code that sits on top of the C library sounds like the most common solution to me. You can go a long way with a generic library on top of a C library. Lots of generic libraries end up calling BLAS/LAPACK.

Regardless, the burden is on those opposed to alias this to provide a solution.
March 16, 2021
On Tuesday, 16 March 2021 at 16:55:47 UTC, bachmeier wrote:
> On Tuesday, 16 March 2021 at 16:08:46 UTC, H. S. Teoh wrote:
>> On Tue, Mar 16, 2021 at 03:18:49PM +0000, bachmeier via Digitalmars-d wrote:
>>> On Monday, 15 March 2021 at 17:18:19 UTC, H. S. Teoh wrote:
>>> 
>>> > Although there are definitely cases for which it's actually useful, the problems it brings along make it of questionable value as a general language feature.  I'd also be in favor of getting rid of it, at least from classes, if not completely. (The latter is probably impossible; quite a lot of my own code relies on it, and I imagine I'm not the only one using it among the users of D.)
>>> 
>>> A feature that can't be used wrong isn't much of a feature. alias this is easy to use correctly and provides immense value. The removal of useful features is not a good solution to bad program design.
>>
>> I used to have your stance.  But these days, I'm starting to realize more and more that implicit conversions are almost always a bad idea. They are convenient and fast in the beginning when you're trying to get the job done, but in the long term, they hurt readability and maintainability.  I've come to realize that when the code relies too much on this kind of implicit conversion, esp. via alias this, it's often a sign of poor code structure. It's a code smell.  It works, but smells bad, and eventually you realize that it *is* bad.
>
> If you're calling into a C library for matrix operations, but you have three or more strategies for allocating the underlying memory, alias this is reasonable. Otherwise you're writing *extremely* verbose code or you need to engage in extraordinary code duplication or you're writing a bunch of ugly generic code that sits on top of the C library. alias this is a clean, trivial solution in this case.

Meta programing is meant to solve the verbose code problem. What is preventing you from using tools such as templates and string mixins?

- Alex