June 19, 2021

On Saturday, 19 June 2021 at 10:40:45 UTC, Bradley Chatha wrote:

>

What are the chances though that the path/syntax can be changed at this point though, mostly in regards to convincing people? Not just for this suggestion, but any suggestion/criticism towards DIP 1000 in general?

I think it is mostly up to the other compiler devs to convince Walter? I don't think there is anything I can do anyway.

>

My main worry is that we'll end up with an inflexible, hard to understand system that doesn't even do the job right. Yet another tacked on feature for the language, etc.

This is a good reason to have an experimental branch and let new features sit there until people get enough experience with them.

June 19, 2021

On Saturday, 19 June 2021 at 13:47:06 UTC, Ola Fosheim Grøstad wrote:

>

This is a good reason to have an experimental branch and let new features sit there until people get enough experience with them.

DIP1000 is still behind a preview switch, which you could consider an experimental branch, and it has been for five years now. I don't think incubation time is the problem here, but rather the lack of documentation and thorough testing. Now we have some code bases (most notably Phobos) that compile with -dip1000 but only because of hacks and bugs such as inout implies return, pure implies scope, address of ref isn't scope, conflation of return-ref and return-scope, getting a slice to a scope static array is allowed, separate compilation isn't checked, ...

Those were great in the short term because they minimize the amount of breaking changes when turning on -dip1000. In the long term, all this code relying on accepts-invalid bugs is annoying to fix though.

June 19, 2021

On Saturday, 19 June 2021 at 09:43:18 UTC, ag0aep6g wrote:

>

A quick and easy fix could be introducing return(ref) and return(scope), allowing the programmer to pick what return binds to. Then opIndex can be written this way:


ref float opIndex(size_t i) return(scope) {
return this._elements[i];
}

No thanks. The compiler still has ambiguity between

ref float opIndex(return(scope) ref __this, size_t i);
return(scope) ref float opIndex(ref __this, size_t i);

It's simpler and better if return attribute outside the parameter list always binds to this. Unless there is some reason you might want to annotate the return type as return? I can't think of any.

>

I'm afraid DIPs 25 and 1000 are falling short.

In the sense that you can't have deep scope, true. But I think DIP1000 was deliberately designed to not address that, for simplicity. I suggest that we leave fixing that for a potential future DIP.

Just by fixing that opIndex example we still have the ability to define custom types that can be used for deep lifetime checking.

June 19, 2021

On Saturday, 19 June 2021 at 14:39:01 UTC, Dukc wrote:

>

It's simpler and better if return attribute outside the parameter list always binds to this. Unless there is some reason you might want to annotate the return type as return? I can't think of any.

I think you misunderstand. return does bind to this. But it can bind to two different aspects of this: (1) ref or (2) scope.

Currently, you cannot freely choose which aspect of this you want to be return. The opIndex example fails because return is applied to the wrong aspect, and the programmer can't override it.

June 19, 2021

On Saturday, 19 June 2021 at 14:37:24 UTC, Dennis wrote:

>

Those were great in the short term because they minimize the amount of breaking changes when turning on -dip1000. In the long term, all this code relying on accepts-invalid bugs is annoying to fix though.

And the worst of it, the bugs cannot be easily fixed because they would break Phobos, as you outlined in the first post of your series.

I think it was a mistake to declare Phobos -dip1000 compilant with all those issues still around. I'd much rather have a non-Phobos -dip1000 that behaves as it's supposed to.

June 19, 2021

On Saturday, 19 June 2021 at 14:39:01 UTC, Dukc wrote:

>

No thanks. The compiler still has ambiguity between

ref float opIndex(return(scope) ref __this, size_t i);
return(scope) ref float opIndex(ref __this, size_t i);

It's simpler and better if return attribute outside the parameter list always binds to this.

There is no ambiguity, return and scope outside the parameter list always bind to this, whether you put them on the left or right.

scope int* f(); // Error: function `onlineapp.f` functions cannot be `scope`
int* g() scope; // Error: function `onlineapp.g` functions cannot be `scope`

(Nice error message btw)

June 19, 2021

On Saturday, 19 June 2021 at 14:48:45 UTC, ag0aep6g wrote:

>

I think you misunderstand. return does bind to this. But it can bind to two different aspects of this: (1) ref or (2) scope.

Currently, you cannot freely choose which aspect of this you want to be return. The opIndex example fails because return is applied to the wrong aspect, and the programmer can't override it.

Ah thanks, let's try again. So the member function rewritten would look like

ref float opIndex(return ref float[] vector, size_t i){
   return vector[i];
}

So the problem is that return allows returning the vector array itself by reference, but not any of it's elements.

I think this function should compile, return or no. DIP1000 is not supposed to be transitive, so it should only check returning vector itself by reference, but not anything that it refers to.

However, the user still may want to annotate the vector parameter as return, because that lets the client code to ensure that the reference to vector[i] won't live longer than vector.

June 19, 2021

On Saturday, 19 June 2021 at 15:18:20 UTC, Dukc wrote:

>
ref float opIndex(return ref float[] vector, size_t i){
   return vector[i];
}

So the problem is that return allows returning the vector array itself by reference, but not any of it's elements.

I think this function should compile, return or no. DIP1000 is not supposed to be transitive, so it should only check returning vector itself by reference, but not anything that it refers to.

It currently does compile. float[] vector is assumed to have infinite lifetime here, so you can return its elements by ref just fine. You cannot call this opIndex on a slice of stack memory, then your signature has to add the scope keyword:

ref float opIndex(return ref scope float[] vector, size_t i){
   return vector[i];
}

And then the compiler needs to know that the returned float's lifetime is bound to the stack memory you put in, so then you want return scope semantics (which you can't get here because there's a ref return and a ref param.

June 19, 2021

On Saturday, 19 June 2021 at 15:27:24 UTC, Dennis wrote:

>

It currently does compile. float[] vector is assumed to have infinite lifetime here, so you can return its elements by ref just fine. You cannot call this opIndex on a slice of stack memory, then your signature has to add the scope keyword:

ref float opIndex(return ref scope float[] vector, size_t i){
   return vector[i];
}

And then the compiler needs to know that the returned float's lifetime is bound to the stack memory you put in, so then you want return scope semantics (which you can't get here because there's a ref return and a ref param.

I'm not sure that scope ref should have any different semantics from ref anyway. If vector were passed by value it'd work with stack memory. But for that to work with operator overloading in same time, we'd need a non-ref this argument, or overloading with static or UFCS functions.

Okay, now I'm not sure what would be the best course of action.

June 19, 2021

On Saturday, 19 June 2021 at 14:37:24 UTC, Dennis wrote:

>

DIP1000 is still behind a preview switch, which you could consider an experimental branch, and it has been for five years now. I don't think incubation time is the problem here, but rather the lack of documentation and thorough testing.

I don't know if people use switches all that much? With an experimental branch most hobbyists would use it to get the latest features, so I think it would lead to more use of upcoming features... but I don't know for sure.