February 02, 2014
On Sat, 01 Feb 2014 20:17:47 -0800, Frank Bauer <y@z.com> wrote:

> On Sunday, 2 February 2014 at 03:38:08 UTC, Adam Wilson wrote:
>> You have no idea if a library you are using is written using the GC.
>
> Well, the library writer might tell me, if she used GC(T) (the linker might as well) ...
>
>> If you don't use the GC, by definition it will not run, unless a library you depend on uses it.
>
> big UNLESS!

Maybe, but my point is that even with no allocations in phobos, you'd have to verify that ALL the libraries you use don't GC allocate. That's why so many people in the ARC camp want to make it the only GC system in D. Multiple GC systems increase your cognitive load considerably.

-- 
Adam Wilson
GitHub/IRC: LightBender
Aurora Project Coordinator
February 02, 2014
On Sunday, 2 February 2014 at 03:38:03 UTC, Andrei Alexandrescu wrote:
> Whoa, this won't work without an explosion in language complexity.

The complexity is already there, it is just hidden. But most the capacity to deal with it is already there too:

Owning!T is just a struct with ~this() { free(me); }. Referencing counting is just a struct with this(this) { payload.ref++; } ~this() { payload.ref--; } (with a few optimizations to remove ref++; ref--;, which IMO should be there anyway!)

Borrowed is a reference we can use or copy, but must not free (delete is deprecated!) and ought not store.

GC is a reference that we don't have to free AND is ok to store.



The language just conflates the latter two. And the spec even gives us some hope that it isn't supposed to with the scope storage class, though IMO the difference is more of a type thing than a storage class thing. A GC reference should implicitly convert to a borrowed reference (e.g. alias slice this;) but not vice versa. The only way to go from borrowed -> GC (or any other really) would be cowboy it with cast() or copying the contents.



BTW I like a lot of the ideas Rust has in this regard, but I don't think we have to go all the way they did. But having:

char[] foo = new char[](1024);

and

char[1024] buffer;
char[] foo = buffer[];


both work and yield exactly the same type is trouble.
February 02, 2014
On Sunday, 2 February 2014 at 04:26:16 UTC, Adam D. Ruppe wrote:
> On Sunday, 2 February 2014 at 03:38:03 UTC, Andrei Alexandrescu wrote:
>> Whoa, this won't work without an explosion in language complexity.
>
> The complexity is already there, it is just hidden. But most the capacity to deal with it is already there too:
>
> Owning!T is just a struct with ~this() { free(me); }. Referencing counting is just a struct with this(this) { payload.ref++; } ~this() { payload.ref--; } (with a few optimizations to remove ref++; ref--;, which IMO should be there anyway!)
>
> Borrowed is a reference we can use or copy, but must not free (delete is deprecated!) and ought not store.
>
> GC is a reference that we don't have to free AND is ok to store.
>
>
>
> The language just conflates the latter two. And the spec even gives us some hope that it isn't supposed to with the scope storage class, though IMO the difference is more of a type thing than a storage class thing. A GC reference should implicitly convert to a borrowed reference (e.g. alias slice this;) but not vice versa. The only way to go from borrowed -> GC (or any other really) would be cowboy it with cast() or copying the contents.
>
>
>
> BTW I like a lot of the ideas Rust has in this regard, but I don't think we have to go all the way they did. But having:
>
> char[] foo = new char[](1024);
>
> and
>
> char[1024] buffer;
> char[] foo = buffer[];
>
>
> both work and yield exactly the same type is trouble.


I see light ...

There is one little complication of owning pointers interacting with borrowed pointers that might prevent a straightforward approach (I'm sure there's more): owning pointers must not go out of scope or be reassigned as long as there are outstanding references to them alive (i.e. in scope as well).

I don't see ATM how this could be done at zero cost without intrinsic compiler support. Only the compiler could enforce this free of cost as far as I see.
February 02, 2014
On Sat, 01 Feb 2014 20:43:37 -0800, Frank Bauer <y@z.com> wrote:

> On Sunday, 2 February 2014 at 04:26:16 UTC, Adam D. Ruppe wrote:
>> On Sunday, 2 February 2014 at 03:38:03 UTC, Andrei Alexandrescu wrote:
>>> Whoa, this won't work without an explosion in language complexity.
>>
>> The complexity is already there, it is just hidden. But most the capacity to deal with it is already there too:
>>
>> Owning!T is just a struct with ~this() { free(me); }. Referencing counting is just a struct with this(this) { payload.ref++; } ~this() { payload.ref--; } (with a few optimizations to remove ref++; ref--;, which IMO should be there anyway!)
>>
>> Borrowed is a reference we can use or copy, but must not free (delete is deprecated!) and ought not store.
>>
>> GC is a reference that we don't have to free AND is ok to store.
>>
>>
>>
>> The language just conflates the latter two. And the spec even gives us some hope that it isn't supposed to with the scope storage class, though IMO the difference is more of a type thing than a storage class thing. A GC reference should implicitly convert to a borrowed reference (e.g. alias slice this;) but not vice versa. The only way to go from borrowed -> GC (or any other really) would be cowboy it with cast() or copying the contents.
>>
>>
>>
>> BTW I like a lot of the ideas Rust has in this regard, but I don't think we have to go all the way they did. But having:
>>
>> char[] foo = new char[](1024);
>>
>> and
>>
>> char[1024] buffer;
>> char[] foo = buffer[];
>>
>>
>> both work and yield exactly the same type is trouble.
>
>
> I see light ...
>
> There is one little complication of owning pointers interacting with borrowed pointers that might prevent a straightforward approach (I'm sure there's more): owning pointers must not go out of scope or be reassigned as long as there are outstanding references to them alive (i.e. in scope as well).
>
> I don't see ATM how this could be done at zero cost without intrinsic compiler support. Only the compiler could enforce this free of cost as far as I see.

I believe it should be possible to argue for the compiler support as long as it doesn't add any language level complexity. I too like how this works.

However, full ARC presents quite a few more problems. You will certainly need to add at least one more keyword to the language ('arc' anyone?) and a metric ton of compiler support.

-- 
Adam Wilson
GitHub/IRC: LightBender
Aurora Project Coordinator
February 02, 2014
On Sunday, 2 February 2014 at 04:23:35 UTC, Adam Wilson wrote:
> Maybe, but my point is that even with no allocations in phobos, you'd have to verify that ALL the libraries you use don't GC allocate. That's why so many people in the ARC camp want to make it the only GC system in D. Multiple GC systems increase your cognitive load considerably.

Good point. What we DON'T want is a library that comes in MySuperLib-GC, MySuperLib-ARC, MySuperLib-Owning and MySuperLib-Borrowed flavors.

But I don't think that is necessary.

A library function would typically take arguments by reference aka as a Borrowed(T). GC(T), ARC(T) and Owning(T) convert equally well to Borrowed(T). So somebody who uses only GC(T) in her code could use the library just as easily as someone who prefers Owning(T). The library would be compatible with the two, because it does not own the (reference to the) passed object. GC(T) or Owning(T) at the call site would free the object automatically (at the next collection cycle or when leaving the scope). Everybody is happy!

All that is left for the caller is to choose whether she wants to use a library that uses GC *internally*. Interaction is possible in every combination:

1. I use GC(T),     the library uses GC(T) internally     -> works (with GC),
2. I use Owning(T), the library uses GC(T) internally     -> works (with GC),
3. I use GC(T),     the library uses Owning(T) internally -> works (with GC),
4. I use Owning(T), the library uses Owning(T) internally -> works (w/o GC).
February 02, 2014
Of course to make everyone in 4 happy (i.e. me;) there would have to be a Phobos that uses Owning(T) internally exclusively.
February 02, 2014
On 2/1/14, 8:18 PM, Frank Bauer wrote:
> On Sunday, 2 February 2014 at 03:38:03 UTC, Andrei Alexandrescu wrote:
>> Whoa, this won't work without an explosion in language complexity.
>>
>> Andrei
>
> Only daydreaming ...

No, it's a nightmare.

Andrei
February 02, 2014
On Sunday, 2 February 2014 at 05:30:02 UTC, Andrei Alexandrescu wrote:
> On 2/1/14, 8:18 PM, Frank Bauer wrote:
>> On Sunday, 2 February 2014 at 03:38:03 UTC, Andrei Alexandrescu wrote:
>>> Whoa, this won't work without an explosion in language complexity.
>>>
>>> Andrei
>>
>> Only daydreaming ...
>
> No, it's a nightmare.
>
> Andrei

^^ Lets do it while we're young ...
February 02, 2014
On 2/1/14, 9:34 PM, Frank Bauer wrote:
> On Sunday, 2 February 2014 at 05:30:02 UTC, Andrei Alexandrescu wrote:
>> On 2/1/14, 8:18 PM, Frank Bauer wrote:
>>> On Sunday, 2 February 2014 at 03:38:03 UTC, Andrei Alexandrescu wrote:
>>>> Whoa, this won't work without an explosion in language complexity.
>>>>
>>>> Andrei
>>>
>>> Only daydreaming ...
>>
>> No, it's a nightmare.
>>
>> Andrei
>
> ^^ Lets do it while we're young ...

Sure. While you're young typecheck this:

class A {
   auto stuff() { ...; return this; }
}


Andrei
February 02, 2014
On Sunday, 2 February 2014 at 05:41:53 UTC, Andrei Alexandrescu wrote:
> Sure. While you're young typecheck this:
>
> class A {
>    auto stuff() { ...; return this; }
> }
>
>
> Andrei

It would be a Borrowed!A, I would say, no matter how an A is allocated. A GC!A, an ARC!A and an Owning!A convert equally well to a Borrowed!A. As long as the Borrowed!A is in use (i.e. scope) after stuff() returns, the A object must not be freed (compiler enforced). Would that make sense?