April 10
On Monday, 8 April 2024 at 20:10:24 UTC, Richard (Rikki) Andrew Cattermole wrote:
> On 09/04/2024 6:18 AM, Atila Neves wrote:
>> On Sunday, 17 March 2024 at 15:35:40 UTC, Paul Backus wrote:
>>> On Sunday, 17 March 2024 at 06:51:23 UTC, Richard (Rikki) Andrew Cattermole wrote:
>>>> [...]
>>>
>>> Yet another proposal for a humongous language feature to solve a problem that can already be solved without it.
>>>
>>> It is possible to achieve temporal safety in D already with `scope` (DIP 1000) and `@system` variables (DIP 1035). The ergonomics are not great, but they can be improved (e.g., with built-in move-on-last-use).
>>>
>>> This proposal specifically has the same problem as `@live`: it splits `@safe` code into separate "new `@safe`" and "old `@safe`" dialects, which are mutually incompatible.
>>>
>>> The ideas themselves are not terrible. I would be interested to see what this looks like implemented in a research language. But I do not think it has any place in D.
>> 
>> I second all of the above.
>
> Just so we are clear, DIP1000 is not able to provide memory safety on a single thread, let alone multiple.
>
> It is missing the child/parent relationship to prevent:
>
> ```d
> Parent* parent;
> Field* child = &parent.field;
> parent.destroy;
> Field value = *child;
> ```

DIP1000 depends on lifetimes and RAII, and in a language like D with constructors and destructors I struggle to find a reason to write `parent.destroy`. This works as intended, in the sense that it fails to compile:

```
    Field* child;
    {
        Parent parent;
        child = &parent.field;
    }
    Field value = *child;
```

It's the same reason why I don't understand "Logic errors such as trying to read from an unopened file" - why would a file be unopened?
April 11
On 11/04/2024 7:17 AM, Atila Neves wrote:
> On Monday, 8 April 2024 at 20:10:24 UTC, Richard (Rikki) Andrew Cattermole wrote:
>> On 09/04/2024 6:18 AM, Atila Neves wrote:
>>> On Sunday, 17 March 2024 at 15:35:40 UTC, Paul Backus wrote:
>>>> On Sunday, 17 March 2024 at 06:51:23 UTC, Richard (Rikki) Andrew Cattermole wrote:
>>>>> [...]
>>>>
>>>> Yet another proposal for a humongous language feature to solve a problem that can already be solved without it.
>>>>
>>>> It is possible to achieve temporal safety in D already with `scope` (DIP 1000) and `@system` variables (DIP 1035). The ergonomics are not great, but they can be improved (e.g., with built-in move-on-last-use).
>>>>
>>>> This proposal specifically has the same problem as `@live`: it splits `@safe` code into separate "new `@safe`" and "old `@safe`" dialects, which are mutually incompatible.
>>>>
>>>> The ideas themselves are not terrible. I would be interested to see what this looks like implemented in a research language. But I do not think it has any place in D.
>>>
>>> I second all of the above.
>>
>> Just so we are clear, DIP1000 is not able to provide memory safety on a single thread, let alone multiple.
>>
>> It is missing the child/parent relationship to prevent:
>>
>> ```d
>> Parent* parent;
>> Field* child = &parent.field;
>> parent.destroy;
>> Field value = *child;
>> ```
> 
> DIP1000 depends on lifetimes and RAII, and in a language like D with constructors and destructors I struggle to find a reason to write `parent.destroy`. This works as intended, in the sense that it fails to compile:
> 
> ```
>      Field* child;
>      {
>          Parent parent;
>          child = &parent.field;
>      }
>      Field value = *child;
> ```

Yes, because of the explicit scope creation. The compiler can see it cross scopes, but not within a scope this requires tracking of values and their order of invalidation.

> It's the same reason why I don't understand "Logic errors such as trying to read from an unopened file" - why would a file be unopened?

Accidental, different scope states (conditional/function calls), explicit closing, events handled automatically by OS.

A lot of reasons.
April 10
On Wednesday, 10 April 2024 at 19:23:17 UTC, Richard (Rikki) Andrew Cattermole wrote:
>
> On 11/04/2024 7:17 AM, Atila Neves wrote:
>> On Monday, 8 April 2024 at 20:10:24 UTC, Richard (Rikki) Andrew Cattermole wrote:
>>> On 09/04/2024 6:18 AM, Atila Neves wrote:
>>>> On Sunday, 17 March 2024 at 15:35:40 UTC, Paul Backus wrote:
>>>>> On Sunday, 17 March 2024 at 06:51:23 UTC, Richard (Rikki) Andrew Cattermole wrote:
>>>>>> [...]
>>>>>
>>>>> Yet another proposal for a humongous language feature to solve a problem that can already be solved without it.
>>>>>
>>>>> It is possible to achieve temporal safety in D already with `scope` (DIP 1000) and `@system` variables (DIP 1035). The ergonomics are not great, but they can be improved (e.g., with built-in move-on-last-use).
>>>>>
>>>>> This proposal specifically has the same problem as `@live`: it splits `@safe` code into separate "new `@safe`" and "old `@safe`" dialects, which are mutually incompatible.
>>>>>
>>>>> The ideas themselves are not terrible. I would be interested to see what this looks like implemented in a research language. But I do not think it has any place in D.
>>>>
>>>> I second all of the above.
>>>
>>> Just so we are clear, DIP1000 is not able to provide memory safety on a single thread, let alone multiple.
>>>
>>> It is missing the child/parent relationship to prevent:
>>>
>>> ```d
>>> Parent* parent;
>>> Field* child = &parent.field;
>>> parent.destroy;
>>> Field value = *child;
>>> ```
>> 
>> DIP1000 depends on lifetimes and RAII, and in a language like D with constructors and destructors I struggle to find a reason to write `parent.destroy`. This works as intended, in the sense that it fails to compile:
>> 
>> ```
>>      Field* child;
>>      {
>>          Parent parent;
>>          child = &parent.field;
>>      }
>>      Field value = *child;
>> ```
>
> Yes, because of the explicit scope creation. The compiler can see it cross scopes, but not within a scope this requires tracking of values and their order of invalidation.

Unless I'm missing something, that's exactly what DIP1000 does? How else would "order of invalidation" work except through scopes? Explicit destruction? Why do that??

>> It's the same reason why I don't understand "Logic errors such as trying to read from an unopened file" - why would a file be unopened?
>
> Accidental, different scope states (conditional/function calls),

What would an example of that look like?

> explicit closing

Doctor, doctor, it hurts when...

>, events handled automatically by OS.

Example?

> A lot of reasons.

I haven't encountered any; I'm not saying they don't exist, I'm saying that in my experience they're rare enough that they're approximately zero. I don't think that's ever happened since I stopped writing C. If one creates a file, it's open. If the file is no longer in scope, it's closed.

April 11
On 11/04/2024 7:31 AM, Atila Neves wrote:
> On Wednesday, 10 April 2024 at 19:23:17 UTC, Richard (Rikki) Andrew Cattermole wrote:
>> Yes, because of the explicit scope creation. The compiler can see it cross scopes, but not within a scope this requires tracking of values and their order of invalidation.
> 
> Unless I'm missing something, that's exactly what DIP1000 does? How else would "order of invalidation" work except through scopes? Explicit destruction? Why do that??

See my earlier example:

```d
Parent* parent;
Field* child = &parent.field;
parent.destroy;
Field value = *child;
```

That simply shouldn't compile.

One single scope, and it absolutely should be under DIP1000's purview.

This is critical for owning data structures (which can include memory allocators) for it to be solved.

Note: destruction also includes assignments to the variable that had contained the data structure.

```d
DS ds = ...;
Item* item = ds[...];
ds = ...;
Item value = *item;
```

Same exact pattern.

>>> It's the same reason why I don't understand "Logic errors such as trying to read from an unopened file" - why would a file be unopened?
>>
>> Accidental, different scope states (conditional/function calls),
> 
> What would an example of that look like?

```d
mayCloseOnSpecificInput(file);

file.read(); // may or may not be closed
```

Add an if/else block to it as well, well... Fun.

>> explicit closing
> 
> Doctor, doctor, it hurts when...

And like goto's we don't allow you to skip variable declarations.

Don't explicitly close and not handle the branches correctly.

Doesn't mean we shouldn't have compiler assistance to prevent you from making this mistake.

>> , events handled automatically by OS.
> 
> Example?

For a socket, peer closed connection. A normally occurring event, that kills the handle automaticaly.

>> A lot of reasons.
> 
> I haven't encountered any; I'm not saying they don't exist, I'm saying that in my experience they're rare enough that they're approximately zero. I don't think that's ever happened since I stopped writing C. If one creates a file, it's open. If the file is no longer in scope, it's closed.

For context: a file representation is the classic example from the 80's for type state analysis. However there was a giant thread only a couple weeks back wanting nullability type state checks.

Notice how a lot of languages now have nullability analysis in them? Yeah. That would be a much better example from a practical stand point.
April 13

On Wednesday, 10 April 2024 at 19:47:03 UTC, Richard (Rikki) Andrew Cattermole wrote:

>

On 11/04/2024 7:31 AM, Atila Neves wrote:

>

Unless I'm missing something, that's exactly what DIP1000 does? How else would "order of invalidation" work except through scopes? Explicit destruction? Why do that??

See my earlier example:

Parent* parent;
Field* child = &parent.field;
parent.destroy;
Field value = *child;

That simply shouldn't compile.

Assuming you meant destroy(*parent); instead of destroying only the pointer to it.

destroy runs the destructor of the object, but it doesn't free it. It even sets it to it's .init value so that it's known exactly what any further calls on the object will do. So your example is safe.

I know, what you're saying is that one can't give @safe access to a field that is deallocated when the struct is destroyed even with a scoped reference, because the struct can be destroyed before the reference expires.

We've probably been through this before: one can, but only inside a callback such as borrow for SafeRefCounted, that locks the data structure preventing destruction while the callback is executed.

1 2
Next ›   Last »