January 26, 2023

On Monday, 23 January 2023 at 08:49:50 UTC, Richard (Rikki) Andrew Cattermole wrote:

>
Vector!int vector;
vector ~= 3;

auto borrowed = vector[0];
func(borrowed);

void func(scope ref int value) {
	
}

Basically right now we're missing the lifetime checks surrounding borrowed & function parameter. Everything else is do-able right now, even if it isn't as cheap as it could be (like RC eliding).

I'm writing a language with borrowing and ref counting (Neat), and this is not a valid borrow. Basically you don't want to take on borrowing with variables that are mutable by default, because then you're asking for things like:

Vector!int vector;
vector ~= 3;
void evil() { vector = Vector!int.init; }

auto borrowed = vector[0];
func(borrowed);

void func(scope ref int value) {
  // destroy the last non-borrowed reference to vector, where is your God now?
  evil;
January 26, 2023

On Thursday, 26 January 2023 at 06:55:41 UTC, FeepingCreature wrote:

>

On Monday, 23 January 2023 at 08:49:50 UTC, Richard (Rikki) Andrew Cattermole wrote:

>
Vector!int vector;
vector ~= 3;

auto borrowed = vector[0];
func(borrowed);

void func(scope ref int value) {
	
}

Basically right now we're missing the lifetime checks surrounding borrowed & function parameter. Everything else is do-able right now, even if it isn't as cheap as it could be (like RC eliding).

I'm writing a language with borrowing and ref counting (Neat), and this is not a valid borrow. Basically you don't want to take on borrowing with variables that are mutable by default, because then you're asking for things like:

Vector!int vector;
vector ~= 3;
void evil() { vector = Vector!int.init; }

auto borrowed = vector[0];
func(borrowed);

void func(scope ref int value) {
  // destroy the last non-borrowed reference to vector, where is your God now?
  evil;

Addendum: This idiom is impossible in Rust because the equivalent of void evil() already captures vector. But nested functions are an essential part of D. This is why you cannot bolt borrowing onto a language that has been designed around a garbage collector; it needs support at every level. (Like variables being rvalue by default, cough.)

January 28, 2023

On Sunday, 22 January 2023 at 15:28:53 UTC, Atila Neves wrote:

>

I'm pretty much convinced we need isolated. This is very similar to why the language as it exists today doesn't allow a library author to write a vector type that can be appended to, which... is the main reason one would use a vector to begin with.

Some allocators (GC?) might have a @safe deallocate function but most (all except the GC?) can't due to aliasing, and that requires isolated.

isolated would be nice, but for now we can model it with a struct so that this works:

class Mallocator : IAllocator
{
    import core.stdc.stdlib : free, malloc;

    void* safeAllocate(size_t n) @trusted
    {
        return malloc(n);
    }

    void safeDeallocate(Isolated!(void*) ip) @trusted
    {
        ip.unwrap.free;
    }
}

void main()
{
    IAllocator a = new Mallocator;
    scope m = a.safeAllocate(4);
    auto ip = (() @trusted => assumeIsolated(a.safeAllocate(4)))();
    a.safeDeallocate(ip.move);
    assert(ip.unwrap == null);
}

Working code:
https://github.com/ntrel/stuff/blob/master/typecons/isolated.d

Isolated could go in std.typecons.

January 30, 2023
On 1/28/23 16:56, Nick Treleaven wrote:
> On Sunday, 22 January 2023 at 15:28:53 UTC, Atila Neves wrote:
>> I'm pretty much convinced we need isolated. This is very similar to why the language as it exists today doesn't allow a library author to write a vector type that can be appended to, which... is the main reason one would use a vector to begin with.
>>
>> Some allocators (GC?) might have a @safe deallocate function but most (all except the GC?) can't due to aliasing, and that requires isolated.
> 
> `isolated` would be nice, but for now we can model it with a struct so that this works:
> ```d
> class Mallocator : IAllocator
> {
>      import core.stdc.stdlib : free, malloc;
> 
>      void* safeAllocate(size_t n) @trusted
>      {
>          return malloc(n);
>      }
> 
>      void safeDeallocate(Isolated!(void*) ip) @trusted
>      {
>          ip.unwrap.free;
>      }
> }
> 
> void main()
> {
>      IAllocator a = new Mallocator;
>      scope m = a.safeAllocate(4);
>      auto ip = (() @trusted => assumeIsolated(a.safeAllocate(4)))();
>      a.safeDeallocate(ip.move);
>      assert(ip.unwrap == null);
> }
> ```
> Working code:
> https://github.com/ntrel/stuff/blob/master/typecons/isolated.d
> 
> Isolated could go in std.typecons.

Isolated is not sufficient, you also have to guarantee the pointer was allocated with `malloc`.
January 30, 2023

On Monday, 30 January 2023 at 01:07:32 UTC, Timon Gehr wrote:

> >

Working code:
https://github.com/ntrel/stuff/blob/master/typecons/isolated.d

Isolated could go in std.typecons.

Isolated is not sufficient, you also have to guarantee the pointer was allocated with malloc.

This could be accomplished with building a wrapper type over malloced pointers. @safe free would accept only them, not any isolated pointer.

January 30, 2023
On Monday, 30 January 2023 at 01:07:32 UTC, Timon Gehr wrote:
> On 1/28/23 16:56, Nick Treleaven wrote:
>> [snip]
>> Isolated could go in std.typecons.
>
> Isolated is not sufficient, you also have to guarantee the pointer was allocated with `malloc`.

Could you explain in a bit more detail why this is the case? Thanks.
January 30, 2023
On 1/30/23 13:19, jmh530 wrote:
> On Monday, 30 January 2023 at 01:07:32 UTC, Timon Gehr wrote:
>> On 1/28/23 16:56, Nick Treleaven wrote:
>>> [snip]
>>> Isolated could go in std.typecons.
>>
>> Isolated is not sufficient, you also have to guarantee the pointer was allocated with `malloc`.
> 
> Could you explain in a bit more detail why this is the case? Thanks.

https://en.cppreference.com/w/c/memory/free

"The behavior is undefined if the value of ptr does not equal a value returned earlier by malloc(), calloc(), realloc(), or aligned_alloc()."

Undefined behavior is not memory safe.
January 31, 2023
On 31/01/2023 1:17 AM, Dukc wrote:
> On Monday, 30 January 2023 at 01:07:32 UTC, Timon Gehr wrote:
>>> Working code:
>>> https://github.com/ntrel/stuff/blob/master/typecons/isolated.d
>>>
>>> Isolated could go in std.typecons.
>>
>> Isolated is not sufficient, you also have to guarantee the pointer was allocated with `malloc`.
> 
> This could be accomplished with building a wrapper type over `malloc`ed pointers. `@safe` `free` would accept only them, not any isolated pointer.

This is just horrible. You might as well call it DynamicArray which is exactly what I recommend you do, use data structures and not call allocators directly!

Of course we could add ``@require(AllocatorAware)`` and call it a day. That would at least force people to audit their code and realize hey... this isn't something I should be using directly but still allow passing allocators around.
January 30, 2023
On Monday, 30 January 2023 at 12:26:09 UTC, Timon Gehr wrote:
> [snip]
>
> https://en.cppreference.com/w/c/memory/free
>
> "The behavior is undefined if the value of ptr does not equal a value returned earlier by malloc(), calloc(), realloc(), or aligned_alloc()."
>
> Undefined behavior is not memory safe.

Thanks.
January 30, 2023
On Monday, 30 January 2023 at 12:30:01 UTC, Richard (Rikki) Andrew Cattermole wrote:
> On 31/01/2023 1:17 AM, Dukc wrote:
>> 
>> This could be accomplished with building a wrapper type over `malloc`ed pointers. `@safe` `free` would accept only them, not any isolated pointer.
>
> This is just horrible. You might as well call it DynamicArray which is exactly what I recommend you do, use data structures and not call allocators directly!

I don't understand why you keep bringing this up--it's totally beside the point. Obviously most users should not need to use the allocator API directly.

However, if you are *implementing* a data structure like a dynamic array, and you want to support user-supplied custom allocators, then the only way your data structure can be @safe is if the allocator API uses this kind of wrapper type to present a @safe interface.