Jump to page: 1 24  
Page
Thread overview
An exegesis of Walter's reference counted slice
Feb 24, 2015
ketmar
Feb 24, 2015
ketmar
Feb 24, 2015
Walter Bright
Feb 24, 2015
ketmar
Feb 24, 2015
weaselcat
Feb 24, 2015
weaselcat
Feb 24, 2015
ketmar
Feb 24, 2015
H. S. Teoh
Feb 24, 2015
weaselcat
Feb 24, 2015
H. S. Teoh
Feb 24, 2015
ketmar
Feb 24, 2015
Paulo Pinto
Feb 24, 2015
Ivan Timokhin
Feb 25, 2015
Ivan Timokhin
Feb 25, 2015
Ivan Timokhin
Feb 25, 2015
weaselcat
Feb 24, 2015
Marc Schütz
Feb 25, 2015
Marc Schütz
Feb 24, 2015
deadalnix
Feb 25, 2015
Walter Bright
Feb 25, 2015
deadalnix
Feb 25, 2015
Walter Bright
February 24, 2015
I modified Walter's sample code to this: http://dpaste.dzfl.pl/f3d854feede9. It uses malloc for both the array and the reference count, and also uses @trusted minimally. I inserted assert()s here and there to clarify the workings. Nothing big except for the careful use of @trusted.

I'll use this as a basis of some exegesis.

1. The code is a bit more complicated than it should. Overall this is not a biggie; regular D users are not supposed to write reference counted slices casually. But I was bummed that e.g. I found no way to call emplace() @safe-ly.

2. Michel's point (https://issues.dlang.org/show_bug.cgi?id=14221) reveals the largest issue with RC/GC integration. We need to find a fix for it if we want to have the GC lift cycles.

3. opIndex ("here's the magic") is the most interesting part of the proposal. It disallows unsafe use such as:

@safe ref int fun()
{
   auto a = RCArray!int([1, 2, 3]);
   return a[1];
}

Nice. I'd go as far as saying that barring implementation bugs, with DIP25 in tow, and after we fix 14221, it's impossible to get an invalid memory access with RCArray in @safe code. This (we offer a way to design @safe arrays and more generally structs that are @safe) is interesting and important.

That said there is a rub. The part that deallocates memory in the destructor must be @trusted. That is fine, but the trustworthiness of that code depends on the "return" attribute in opIndex. Furthermore, if the author of RCSlice forgets to put "return" there, the compiler won't help - it just allows wrong code like fun() above to compile and run (causing dangling pointer use).

So: does DIP25 allow safe slices? Looks that way, though a proof would be nice. Does it allow other safe interesting structs that own data? Very likely. Does it allow really sophisticated ownership schemes? We need to explore that. Does it protect against bugs in implementations of safe ownership schemes that explicitly release memory? Not too well. I think the prevalent idiom will be to accompany such artifacts with unittests that make sure unsafe uses (such as fun() above) do not compile.


Andrei
February 24, 2015
On 2/24/15 2:40 PM, Andrei Alexandrescu wrote:
> I modified Walter's sample code to this:
> http://dpaste.dzfl.pl/f3d854feede9. It uses malloc for both the array
> and the reference count, and also uses @trusted minimally. I inserted
> assert()s here and there to clarify the workings. Nothing big except for
> the careful use of @trusted.
>
> I'll use this as a basis of some exegesis.
>
> 1. The code is a bit more complicated than it should. Overall this is
> not a biggie; regular D users are not supposed to write reference
> counted slices casually. But I was bummed that e.g. I found no way to
> call emplace() @safe-ly.

I have no problem with underlying complexity of primitive types. Using Objective-C objects is just fine without understanding the implementation.

Note, you need to GC.addRange all the elements if the type has references, or else you cannot have GC pointers in the array. For example, an array of class references could potentially result in those references being collected before the array is gone.

Ironically, if those elements are references, but are reference counted references, then you wouldn't need to addRange. An interesting problem...

> 2. Michel's point (https://issues.dlang.org/show_bug.cgi?id=14221)
> reveals the largest issue with RC/GC integration. We need to find a fix
> for it if we want to have the GC lift cycles.

I think a system of making sure a piece of data is always destroyed in the same thread it was created (unless of course, the thread is gone, in which case it doesn't matter), should be fine.

-Steve
February 24, 2015
On Tue, 24 Feb 2015 11:40:34 -0800, Andrei Alexandrescu wrote:

> 3. opIndex ("here's the magic") is the most interesting part of the proposal. It disallows unsafe use such as:
> 
> @safe ref int fun()
> {
>     auto a = RCArray!int([1, 2, 3]);
>     return a[1];
> }

this is the important part for those who are too lazy to read DIP25 (like me). thank you.

February 24, 2015
On Tuesday, 24 February 2015 at 19:40:35 UTC, Andrei Alexandrescu wrote:
> ...

Off-topic, sorry
Are we still going to get a Trusted block, or just going to use trusted lambdas?(They're kind of ugly TBH)

> But I was bummed that e.g. I found no way to call emplace() @safe-ly.

I assumed emplace would infer @safe?
February 24, 2015
On 2/24/15 11:55 AM, Steven Schveighoffer wrote:
> Note, you need to GC.addRange all the elements if the type has
> references, or else you cannot have GC pointers in the array. For
> example, an array of class references could potentially result in those
> references being collected before the array is gone.
>
> Ironically, if those elements are references, but are reference counted
> references, then you wouldn't need to addRange. An interesting problem...

Could you please add a detailed issue about this? Thanks. -- Andrei

February 24, 2015
On 2/24/15 12:03 PM, weaselcat wrote:
> On Tuesday, 24 February 2015 at 19:40:35 UTC, Andrei Alexandrescu wrote:
>> ...
>
> Off-topic, sorry
> Are we still going to get a Trusted block, or just going to use trusted
> lambdas?(They're kind of ugly TBH)

We're going to lambdas. Ugliness is a feature.

>> But I was bummed that e.g. I found no way to call emplace() @safe-ly.
>
> I assumed emplace would infer @safe?

It currently doesn't properly, probably because it uses T* instead of ref T.


Andrei

February 24, 2015
On Tue, 24 Feb 2015 14:55:14 -0500, Steven Schveighoffer wrote:

> Note, you need to GC.addRange all the elements if the type has references, or else you cannot have GC pointers in the array. For example, an array of class references could potentially result in those references being collected before the array is gone.

heh. yes, i hit this in my `iv.steam.PartialStream` implementation. those occasional crashes was nasty.

> Ironically, if those elements are references, but are reference counted references, then you wouldn't need to addRange. An interesting problem...

actually, it's safe to add GC roots and regions that contains no GC references. it's a little slowdown, as GC must scan that area, but nothing bad happens.

yet you are right, there should be some method to distinguish "gc- agnostic" types. and compiler should be able to infer that...

February 24, 2015
On Tuesday, 24 February 2015 at 20:04:27 UTC, Andrei Alexandrescu wrote:
> On 2/24/15 12:03 PM, weaselcat wrote:
>> On Tuesday, 24 February 2015 at 19:40:35 UTC, Andrei Alexandrescu wrote:
>>> ...
>>
>> Off-topic, sorry
>> Are we still going to get a Trusted block, or just going to use trusted
>> lambdas?(They're kind of ugly TBH)
>
> We're going to lambdas. Ugliness is a feature.
Stroustrup would be proud ;)
February 24, 2015
On Tue, 24 Feb 2015 12:03:36 -0800, Andrei Alexandrescu wrote:

> On 2/24/15 11:55 AM, Steven Schveighoffer wrote:
>> Note, you need to GC.addRange all the elements if the type has references, or else you cannot have GC pointers in the array. For example, an array of class references could potentially result in those references being collected before the array is gone.
>>
>> Ironically, if those elements are references, but are reference counted references, then you wouldn't need to addRange. An interesting problem...
> 
> Could you please add a detailed issue about this? Thanks. -- Andrei

here's the fixed code: http://dpaste.dzfl.pl/5f7dfe237d1e

btw, you have a bug in your implementation:

  (cast(E*) malloc(a.length * uint.sizeof))[0 .. a.length])();

should be:

  (cast(E*) malloc(a.length * E.sizeof))[0 .. a.length])();

sorry, i'm bad in explanations, let the code speak for itself.

February 24, 2015
On Tue, 24 Feb 2015 20:11:17 +0000, weaselcat wrote:

> On Tuesday, 24 February 2015 at 20:04:27 UTC, Andrei Alexandrescu wrote:
>> On 2/24/15 12:03 PM, weaselcat wrote:
>>> On Tuesday, 24 February 2015 at 19:40:35 UTC, Andrei Alexandrescu wrote:
>>>> ...
>>>
>>> Off-topic, sorry Are we still going to get a Trusted block, or just going to use trusted lambdas?(They're kind of ugly TBH)
>>
>> We're going to lambdas. Ugliness is a feature.
> Stroustrup would be proud ;)

yet he made the whole language ugly, instead of making only ugly things ugly. ;-)

« First   ‹ Prev
1 2 3 4