Jump to page: 1 28  
Page
Thread overview
A Refcounted Array Type
Feb 23, 2015
Walter Bright
Feb 24, 2015
Jonathan M Davis
Feb 24, 2015
Walter Bright
Feb 24, 2015
Jonathan M Davis
Feb 24, 2015
Walter Bright
Feb 24, 2015
matovitch
Feb 24, 2015
Namespace
Feb 24, 2015
matovitch
Feb 24, 2015
Namespace
Feb 24, 2015
Ulrich Küttler
Feb 24, 2015
matovitch
Feb 26, 2015
Jonathan M Davis
Feb 24, 2015
bearophile
Feb 24, 2015
Walter Bright
Feb 24, 2015
Max Klyga
Feb 24, 2015
Walter Bright
Feb 24, 2015
weaselcat
Feb 24, 2015
Walter Bright
Feb 24, 2015
weaselcat
Feb 24, 2015
deadalnix
Feb 24, 2015
Chris
Feb 24, 2015
ponce
Feb 24, 2015
Michel Fortin
Feb 24, 2015
Walter Bright
Feb 24, 2015
deadalnix
Feb 25, 2015
Walter Bright
Feb 25, 2015
deadalnix
Feb 25, 2015
Walter Bright
Feb 26, 2015
deadalnix
Feb 26, 2015
Michel Fortin
Feb 27, 2015
deadalnix
Feb 26, 2015
Marc Schütz
Feb 26, 2015
Marc Schütz
Feb 27, 2015
ketmar
Feb 27, 2015
ketmar
Feb 27, 2015
ketmar
Feb 27, 2015
deadalnix
Feb 28, 2015
ketmar
Feb 28, 2015
weaselcat
Feb 28, 2015
Marc Schütz
Mar 03, 2015
ketmar
Mar 03, 2015
ketmar
Mar 03, 2015
Kagamin
Mar 03, 2015
Kagamin
Mar 04, 2015
Kagamin
Mar 04, 2015
Kagamin
Mar 05, 2015
Kagamin
Mar 03, 2015
ketmar
Feb 27, 2015
Marc Schütz
Feb 24, 2015
deadalnix
Feb 25, 2015
Walter Bright
Feb 25, 2015
Marc Schütz
Feb 24, 2015
deadalnix
Mar 05, 2015
monarch_dodra
Mar 05, 2015
Marc Schütz
Mar 05, 2015
monarch_dodra
February 23, 2015
This is pretty straightforward. More could be done:

1. small array optimization
2. support for ranges as constructor args
3. present a range interface
4. support for malloc/free instead of GC
5. bounds checking
6. the array[] and the count could be allocated together
7. array[] could be just a pointer

but the basic idea is there, I didn't want to hide it behind all the other flesh a professional type would have.

Note the return in opIndex(). This is DIP25 at work!

Compile:
    dmd rcarray -unittest -main -dip25

===========================================

struct RCArray(E) {

    this(E[] a)
    {
        array = a.dup;
        start = 0;
        end = a.length;
        count = new int;
        *count = 1;
    }

    ~this()
    {
        if (count && --*count == 0)
            delete array;
    }

    this(this)
    {
        if (count)
            ++*count;
    }

    size_t length()
    {
        return end - start;
    }

    ref E opIndex(size_t i) return // here's the magic
    {
        return array[start + i];
    }

    RCArray opSlice(size_t lwr, size_t upr)
    {
        RCArray result = this;
        result.start = start + lwr;
        result.end = start + upr;
        return result;
    }

  private:
    E[] array;
    size_t start, end;
    int* count;
}

unittest
{
    static int[3] s = [7, 6, 4];
    auto r = RCArray!int(s);
    assert(r.length == 3);
    assert(r[0] == 7);
    assert(r[1] == 6);
    assert(r[2] == 4);
    assert(*r.count == 1);

    {
        auto r2 = r;
        assert(r2[0] == 7);
        assert(r2[1] == 6);
        assert(r2[2] == 4);
        assert(*r.count == 2);

        r[1] = 3;
        assert(r2[0] == 7);
        assert(r2[1] == 3);
        assert(r2[2] == 4);
    }
    assert(*r.count == 1);

    auto r3 = r[1 .. 3];
    r[2] = 9;
    assert(r3[0] == 3);
    assert(r3[1] == 9);

  /+
    ref int test(ref RCArray!int rr)
    {
        return rr[1]; // this gives error
    }
   +/
}
February 23, 2015
On 2/23/15 2:15 PM, Walter Bright wrote:
> This is pretty straightforward.
[snip]

The code builds if you slap a "@safe:" at the top. There is one bug in the compiler: "delete" must not be allowed in @safe code. The destructor must be @trusted.

Understanding that this code (sans delete) is @safe (and the contribution of DIP25 to that) is of paramount importance.

Making it possible to define @safe structs that are still able to return reference to their internals is crucial. It paves the way for truly safe reference counted classes.


Andrei

February 24, 2015
Walter Bright:

> 5. bounds checking

When you go past bounds of a built-in array you get an error located in the user code, while if you put a pre-condition in your Array struct to detect the same errors, you get a run-time error message located in that pre-condition instead. I'd like some way to solve this small problem of giving more correctly located error messages. In Contract programming lingo it's a problem of "blame management" (I'd also like a way to detect some compile-time out-of-bound errors for user-defined collections, but you said this is not worth the effort).

Bye,
bearophile
February 24, 2015
I thought that delete is deprecated, yet here Walter himself promotes a solution that uses it.
Can we *PLEASE* finally deprecate things that are supposed to be deprecated and remove things that are supposed to be removed?

On 2015-02-23 22:15:46 +0000, Walter Bright said:

> This is pretty straightforward. More could be done:
> 
> 1. small array optimization
> 2. support for ranges as constructor args
> 3. present a range interface
> 4. support for malloc/free instead of GC
> 5. bounds checking
> 6. the array[] and the count could be allocated together
> 7. array[] could be just a pointer
> 
> but the basic idea is there, I didn't want to hide it behind all the other flesh a professional type would have.
> 
> Note the return in opIndex(). This is DIP25 at work!
> 
> Compile:
>      dmd rcarray -unittest -main -dip25
> 
> ===========================================
> 
> struct RCArray(E) {
> 
>      this(E[] a)
>      {
>          array = a.dup;
>          start = 0;
>          end = a.length;
>          count = new int;
>          *count = 1;
>      }
> 
>      ~this()
>      {
>          if (count && --*count == 0)
>              delete array;
>      }
> 
>      this(this)
>      {
>          if (count)
>              ++*count;
>      }
> 
>      size_t length()
>      {
>          return end - start;
>      }
> 
>      ref E opIndex(size_t i) return // here's the magic
>      {
>          return array[start + i];
>      }
> 
>      RCArray opSlice(size_t lwr, size_t upr)
>      {
>          RCArray result = this;
>          result.start = start + lwr;
>          result.end = start + upr;
>          return result;
>      }
> 
>    private:
>      E[] array;
>      size_t start, end;
>      int* count;
> }
> 
> unittest
> {
>      static int[3] s = [7, 6, 4];
>      auto r = RCArray!int(s);
>      assert(r.length == 3);
>      assert(r[0] == 7);
>      assert(r[1] == 6);
>      assert(r[2] == 4);
>      assert(*r.count == 1);
> 
>      {
>          auto r2 = r;
>          assert(r2[0] == 7);
>          assert(r2[1] == 6);
>          assert(r2[2] == 4);
>          assert(*r.count == 2);
> 
>          r[1] = 3;
>          assert(r2[0] == 7);
>          assert(r2[1] == 3);
>          assert(r2[2] == 4);
>      }
>      assert(*r.count == 1);
> 
>      auto r3 = r[1 .. 3];
>      r[2] = 9;
>      assert(r3[0] == 3);
>      assert(r3[1] == 9);
> 
>    /+
>      ref int test(ref RCArray!int rr)
>      {
>          return rr[1]; // this gives error
>      }
>     +/
> }


February 24, 2015
On 2/23/2015 4:13 PM, bearophile wrote:
>> 5. bounds checking
>
> When you go past bounds of a built-in array you get an error located in the user
> code, while if you put a pre-condition in your Array struct to detect the same
> errors, you get a run-time error message located in that pre-condition instead.
> I'd like some way to solve this small problem of giving more correctly located
> error messages. In Contract programming lingo it's a problem of "blame
> management" (I'd also like a way to detect some compile-time out-of-bound errors
> for user-defined collections, but you said this is not worth the effort).

This is off-topic. The point of the array class as presented is to show how a memory safe reference counted container can be built.

February 24, 2015
On 2/23/2015 5:01 PM, Max Klyga wrote:
> I thought that delete is deprecated, yet here Walter himself promotes a solution
> that uses it.
> Can we *PLEASE* finally deprecate things that are supposed to be deprecated and
> remove things that are supposed to be removed?

That isn't the point. I could have well have used malloc/free, but I wanted the code example to be about how to make a memory safe ref counted container, not about the details of memory allocation. It demonstrates how 'return ref' is to be used.

February 24, 2015
On Monday, 23 February 2015 at 22:15:54 UTC, Walter Bright wrote:
>     ref E opIndex(size_t i) return // here's the magic

exactly what is this doing? I don't see this explained in DIP25 at all.
February 24, 2015
On 2/23/2015 5:41 PM, weaselcat wrote:
> On Monday, 23 February 2015 at 22:15:54 UTC, Walter Bright wrote:
>>     ref E opIndex(size_t i) return // here's the magic
>
> exactly what is this doing? I don't see this explained in DIP25 at all.

The 'this' is passed by reference. So the 'return' is really 'return ref this', the rest is explained by DIP25.
February 24, 2015
On Tuesday, 24 February 2015 at 02:06:07 UTC, Walter Bright wrote:
> On 2/23/2015 5:41 PM, weaselcat wrote:
>> On Monday, 23 February 2015 at 22:15:54 UTC, Walter Bright wrote:
>>>    ref E opIndex(size_t i) return // here's the magic
>>
>> exactly what is this doing? I don't see this explained in DIP25 at all.
>
> The 'this' is passed by reference. So the 'return' is really 'return ref this', the rest is explained by DIP25.

Oh, I see. That makes a lot more sense.
February 24, 2015
On Monday, February 23, 2015 15:28:21 Andrei Alexandrescu via Digitalmars-d wrote:
> On 2/23/15 2:15 PM, Walter Bright wrote:
> > This is pretty straightforward.
> [snip]
>
> The code builds if you slap a "@safe:" at the top. There is one bug in the compiler: "delete" must not be allowed in @safe code. The destructor must be @trusted.

And delete is supposed to have been deprecated ages ago, but yeah, it _definitely_ shouldn't be considered @safe.

- Jonathan M Davis

« First   ‹ Prev
1 2 3 4 5 6 7 8