April 09, 2017
On Sunday, 9 April 2017 at 20:14:24 UTC, Walter Bright wrote:
> For another, a general mechanism for safe refcounting of classes has eluded us.

The only thing you need to get backed into the language is to make sure things do not escape in uncontrolled manner. Everything else is library.

You wouldn't have this problem if you had listened to myself and Marc when defining DIP1000, because that's exactly what you've been warned about at the time.

Quoting from the timeline ML from Nov 2014:

[...]

Every expression has now has a lifetime associated with it, and can be marked as "scope". it is only possible to assign b to a if b has a lifetime equal or greater than a's.

An infinite lifetime is a lifetime greater or equal than any other lifetime. Expression of infinite lifetime are:
 - literals
 - GC heap allocated objects
 - statics and enums.
 - rvalues of type that do not contain indirections.
 - non scope rvalues.

Dereference share the lifetime of the dereferenced expression (ie infinite lifetime unless the expression is scope). Address of expression shared the lifetime of the base expression, and in addition gain the scope flag.

Comment: Using these rule, we basically define any indirection being of infinite lifetime by default, and we propagate the lifetime when scope. The addition of the scope flag for address of is necessary to disallow taking address->dereference to yield an infinite lifetime.

Variables delcarations (including parameters) have the lifetime of the block they are declared in (2 pitfalls here, I don't have good solution, and the original spec do not as well : #1 destructor, finally, scope statement and #2 closures). Use of these variables shared the lifetime of the variable, unless they qualify for infinite lifetime. Parameter's lifetime are unordered, meaning smaller than infinite, greater than the function's scope, but not equal to each other nor greater/smaller than each others.

[...]

April 09, 2017
On Sunday, 9 April 2017 at 03:26:14 UTC, Walter Bright wrote:
> My previous version did not survive implementation. Here's the revised version. I have submitted it as a DIP, and there's a trial implementation up:
>
>     https://github.com/dlang/dmd/pull/6681

1. This still adds another special case to the language under the guise of not breaking backward compatibility. This is exactly how C++ became the mess it is today.

2. You're adding in ref-counting in an area where it's only available to one very specific part of the language. This is one of the reasons people don't like Go: it offers language features only in specific places at the compiler devs discretion. It would be far better to ACTUALLY add in ref-counting as a real part of the language (like Andrei has been pushing for the past two years, RCStr anyone?). Or to go with deadalnix's scheme which would allow it to be part of the library and @safe. This would allow it to be used in other areas in user code where it makes sense.

For the fourth time:

You're missing the forrest for the trees. D needs a general solution to the problem of GC code in Phobos. This tackles one specific area via special case but leaves every other GC allocation in Phobos, with no way to make it @safe @nogc. These will either require the holistic approach eventually or more special cases.
April 10, 2017
On Sunday, 9 April 2017 at 20:15:46 UTC, Walter Bright wrote:
> On 4/9/2017 1:35 AM, Dukc wrote:
>> object aMemoryLeak;
>>
>> void someFunc()
>> {   throw (aMemoryLeak = new Exception("hello world!"));
>> }
>>
>> Would the compiler warn about this or make the exception normally garbage
>> collected?
>
> That would be a regular gc allocated Exception.

Iternally, would we create a temp Exception with _refcount = 2, and then on assignment to 'aMemoryLeak', change the refcount to 0?

I understand that the compiler would probably optimize that away in this case, but it seems that's a general answer that would work.

So in that case:
1. Do you really need the "_refcount=1" state as currently defined? I'd think the only code which sees this state, has just decremented it from 2 and is about to delete it.

2. Echoing others here: This seems like a general model D could use, where you have refcounted objects, but at any time, a gc reference could be taken, which is indicated by setting the refcount to 0 but leaving the object alive. Is it general? If not, what is special about Exceptions that makes it work here?
April 09, 2017
On 4/9/2017 4:14 PM, Jack Stouffer wrote:
> 1. This still adds another special case to the language under the guise of not
> breaking backward compatibility. This is exactly how C++ became the mess it is
> today.
>
> 2. You're adding in ref-counting in an area where it's only available to one
> very specific part of the language. This is one of the reasons people don't like
> Go: it offers language features only in specific places at the compiler devs
> discretion. It would be far better to ACTUALLY add in ref-counting as a real
> part of the language (like Andrei has been pushing for the past two years, RCStr
> anyone?). Or to go with deadalnix's scheme which would allow it to be part of
> the library and @safe. This would allow it to be used in other areas in user
> code where it makes sense.

You're right, it is a special case. On the other hand, it adds no new syntax at all, and the amount of code breakage should be very small (we'll see). Because of that, it should be upwards compatible if a more general scheme is devised, and it solves an immediate need.


> For the fourth time:
>
> You're missing the forrest for the trees. D needs a general solution to the
> problem of GC code in Phobos. This tackles one specific area via special case
> but leaves every other GC allocation in Phobos, with no way to make it @safe
> @nogc. These will either require the holistic approach eventually or more
> special cases.

I'm not missing it. I'm well aware of that, though it is incorrect that GC code cannot be made @safe. It is implicitly safe.

Disagreeing with something is not the same as being unaware of it, ignoring it, etc. There have been many partial solutions proposed, and many promising ones that turned out to have fatal flaws. Rust has a total solution, but it comes at a very high cost - applications have to be re-engineered to use it, not just add some annotations.

Bob Vila waving his hand with "Just install track lighting" just isn't good enough :-)

  https://www.youtube.com/watch?v=P9FHlhWqbus&feature=youtu.be&t=17

If it was as easy as installing track lighting, why aren't there any languages with pointers and memory safe ref counting (other than Rust)?

D will get memory safe ref counting (DIP1000 enables that), but it will be for structs, not classes. Exceptions are classes.
April 09, 2017
On 4/9/2017 5:12 PM, Andrew Godfrey wrote:
> Is it general?

No.

> If not, what is special about Exceptions that makes it work here?

It only works because all ways that such exceptions can leak are controlled. D doesn't have copy construction for making copies of class references. You couldn't use this scheme, for example, to stuff class references into struct fields.

April 10, 2017
On Monday, 10 April 2017 at 00:48:39 UTC, Walter Bright wrote:
> On 4/9/2017 5:12 PM, Andrew Godfrey wrote:
>> Is it general?
>
> No.
>
>> If not, what is special about Exceptions that makes it work here?
>
> It only works because all ways that such exceptions can leak are controlled. D doesn't have copy construction for making copies of class references. You couldn't use this scheme, for example, to stuff class references into struct fields.

Ok. So then if I have created a refcounted Exception, and later (in another function) I take a reference to it (by stuffing it into a struct field, say), how does that work? What is the value of _refcount after that happens? Is it 0? Or do we take "one more reference to indicate the GC owns it"?
April 09, 2017
On 4/9/2017 6:32 PM, Andrew Godfrey wrote:
> Ok. So then if I have created a refcounted Exception, and later (in another
> function) I take a reference to it (by stuffing it into a struct field, say),
> how does that work?

You can't, because the refcounted Exception will be marked with 'scope' in the catch block.
April 10, 2017
On Monday, 10 April 2017 at 01:54:54 UTC, Walter Bright wrote:
> On 4/9/2017 6:32 PM, Andrew Godfrey wrote:
>> Ok. So then if I have created a refcounted Exception, and later (in another
>> function) I take a reference to it (by stuffing it into a struct field, say),
>> how does that work?
>
> You can't, because the refcounted Exception will be marked with 'scope' in the catch block.

In your proposal, you wrote:

> The only place a refcounted Throwable is ever created is when the following statement is in the user code:

>    throw new E(string);

Did you mean to use the "scope" keyword somewhere in the line above?
April 10, 2017
On Monday, 10 April 2017 at 02:04:35 UTC, Andrew Godfrey wrote:
> On Monday, 10 April 2017 at 01:54:54 UTC, Walter Bright wrote:
>>    throw new E(string);
>
> Did you mean to use the "scope" keyword somewhere in the line above?

No. In the scope the exceptions are instantiated they are not scoped. He meant that if, and only if, they are instantiated in the way mentioned above they are reference counted. If an exception is instantiated otherwise, it is garbage-collected like all other classes. Otherwise, someone could store a refcounted exception into a global object reference. Then the program would have to check for reference count every time when adding or deleting an object reference, slowing down the whole program.

In catch blocks, where the caught exception may or may not be refcounted, they are marked scope so there won't be refcounted classes running wild, only at the catch scope.
April 10, 2017
On 2017-04-09 05:26, Walter Bright wrote:
> My previous version did not survive implementation. Here's the revised
> version. I have submitted it as a DIP, and there's a trial
> implementation up:

What exactly does the user have to do to use throw a RC exception instead of a GC exception?

-- 
/Jacob Carlborg