April 10, 2017
On Monday, 10 April 2017 at 06:17:43 UTC, Dukc wrote:
> 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.

Thanks for explaining!
Now I get it.

I'm just curious: The proposal doesn't mention interop with C++ exception handlers. I don't know the status of that so I'll just ask: Can C++ code catch D exceptions?

April 10, 2017
On Monday, 10 April 2017 at 13:00:52 UTC, Jacob Carlborg wrote:
> 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?

The compiler makes it refcounted if and only if you are "throwing" and "newing" in the same statment, i.e.

    throw new E(); // refcounted

I can see 2 reasons for this:

1) Because you are throwing the new object, your code has no opportunity to misuse the "ref-counted" object.  The exception handler takes over immediately so you have no opportunity to leak the object.  The only place that can reference it will be in the catch chain which will have the cleanup code auto generated by the compiler.

2) No syntax change! Because this isn't a general solution for ref-counted objects, a "no-syntax" feature allows the solution to be rolled out with no library changes which means we aren't investing a lot of unnecessary turmoil in case a new general solution comes out.

After thinking about the proposal the whole thing seems to be quite clever.  I think it takes some time to wrap your mind around why though.

If you want to force a GC exception (though I'm not sure why you would), you could do this:

    auto e = new E(); // GC
    throw e;

I like the discussion about this proposal and I think Walter has addressed the big concerns.  Everyone agrees this only solves a specific problem, but it's a BIG problem and since it doesn't change the syntax it can easily be swapped out for any future general solutions.

Also I think requiring a copy to escape an exception is fine, anyone who doesn't think so doesn't understand the overhead of an exception. But if it's really an issue for people (people who want to force GC exceptions for some reason), you could add a new method to the Exception object that gives you an escapable reference.

Exception getEscapableReference();

A refcounted exception would create a copy, whereas a GC exception would just return itself.
April 10, 2017
Everything looks good except this one line:

On Sunday, 9 April 2017 at 03:26:14 UTC, Walter Bright wrote:
>     throw new E(string);
>

I don't like it for 2 reasons:

a) E e = new E(string); throw e;

   Should be *exactly* the same as

   throw new E(string).

   I think it's obvious why.


b) Using 'new' in @nogc code feels plain wrong.


I think a library method of explicitly creating a ref-counted throwable would be better. One can then do

E e = refCountedThrowable!(E)(string);
throw e;

or, interchangeably,

throw refCountedThrowable!(E)(string);

and

throw new E(string);

would be illegal because new cannot be called from within a @nogc method.

(haven't ever used @nogc so I'm probably wrong)
April 10, 2017
On Monday, 10 April 2017 at 20:52:21 UTC, Lurker wrote:
> Everything looks good except this one line:
>
> On Sunday, 9 April 2017 at 03:26:14 UTC, Walter Bright wrote:
>>     throw new E(string);
>>
>
> I don't like it for 2 reasons:
>
> a) E e = new E(string); throw e;
>
>    Should be *exactly* the same as
>
>    throw new E(string).
>
>    I think it's obvious why.

I agree this "seems wrong" at first, but because D does not have a general solution for reference counted objects, the first case you show can't be implemented safely.  The only reason that "throw new E()" can be safe is that control is ALWAYS and IMMEDIATELY given up to the exception handler, so no general solution is required for reference counted objects because the only place you need to implement reference counted management is in the exception handler itself.

Another way to think of it is that this proposal makes "throw new" into a special operator that is different than composing the "throw" and "new" operations independently. Once you realize this it's easy to understand and explain to others as well, i.e.

"throw"     operator (throw a Throwable object)
"new"       operator (create a GC object)
"throw new" operator (create and throw a reference-counted Throwable object)

Another way this could be done is instead of overloading "throw new", you could introduce a new operator like "throw_ref_counted", but then all code that wants to use ref-counted exceptions needs to change.  I think whether that's justified is debatable but one argument against it is that if/when D implements a general solution for ref-counted objects all the code would need to change AGAIN.

>
> b) Using 'new' in @nogc code feels plain wrong.
>
>
> I think a library method of explicitly creating a ref-counted throwable would be better. One can then do
>
> E e = refCountedThrowable!(E)(string);
> throw e;
>
> or, interchangeably,
>
> throw refCountedThrowable!(E)(string);
>
> and
>
> throw new E(string);
>
> would be illegal because new cannot be called from within a @nogc method.
>
> (haven't ever used @nogc so I'm probably wrong)

Again since D does not support ref-counted objects in general, you can't do this. You could discuss how D should implement general ref-counted objects but that is a HARD problem that's not likely to be solved soon.

The beauty of this proposal is it's a relatively simple solution to a BIG problem.


April 10, 2017
My knee jerk reaction is that it's a very bad thing that "new" means the same thing everywhere in the language (allocate and initialize some GC-managed memory), except for this one case.
April 10, 2017
On 4/10/2017 6:00 AM, Jacob Carlborg wrote:
> What exactly does the user have to do to use throw a RC exception instead of a
> GC exception?

case 1:

   throw new Exception(args...);  // the only way an RC exception
				// is ever created

case 2:

   catch (Exception e) {
       ...
       throw e;  // increments `e`s refcount, if `e` is refcounted
   }

April 10, 2017
On 4/10/2017 2:44 PM, Jonathan Marler wrote:
> Another way to think of it is that this proposal makes "throw new" into a
> special operator that is different than composing the "throw" and "new"
> operations independently. Once you realize this it's easy to understand and
> explain to others as well, i.e.
>
> "throw"     operator (throw a Throwable object)
> "new"       operator (create a GC object)
> "throw new" operator (create and throw a reference-counted Throwable object)

That's right. Thanks for helping out, your explanations are better than mine!

(Once I realized this myself, the implementation got a lot simpler.)

April 11, 2017
On Monday, 10 April 2017 at 23:16:48 UTC, Meta wrote:
> My knee jerk reaction is that it's a very bad thing that "new" means the same thing everywhere in the language (allocate and initialize some GC-managed memory), except for this one case.

`new SomeClass` has never implied GC allocation only - see https://dlang.org/spec/class.html#allocators, though I agree it looks kind of odd to add a special case. But it's hard to miss the benefits - all code that was not @nogc only because of allocating new exceptions and throwing them, becomes @nogc for free. And this is huge - just grep for uses of enforce in Phobos and many other prominent projects.
April 11, 2017
On Monday, 10 April 2017 at 23:16:48 UTC, Meta wrote:
> My knee jerk reaction is that it's a very bad thing that "new" means the same thing everywhere in the language (allocate and initialize some GC-managed memory), except for this one case.

Actually, in addition to user defined overloads (which are deprecated, granted), `new` also can mean stack allocation already! See the `scope` storage class and scope classes.

The language is free to optimize `new` as it sees fit. (IMO, that's the only real justification for it even being a built in language feature instead of an ordinary library function.) The real changes in this proposal are:

1) if the compiler is aware that new will be implemented in such a manner as to not use the gc, it will pass the static @nogc fit.

2) the catch block is restricted a bit in order to enable this optimization.

`new` itself isn't really changing since it was already allowed to do this in cases the compiler can prove its lifetime.
April 11, 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:
>
> [...]

Instead of adding new runtime helper functions like _d_newThrowable and _d_delThrowable, can we leverage the existing (though deprecated) support for class (de)allocators and essentially divide the _d_delThrowable implementation between the destructor and the deallocator member function? This will go hand in hand with the work that Lucia has been doing on making the runtime more generic and reducing the number of special cases in the compiler [1] [2] [3]. Obviously you have done the work already, but in theory at least, with my proposal users should be able to override the memory allocation method in derived exception classes, without any changes to druntime.

[1]: https://github.com/dlang/druntime/pull/1781
[2]: https://github.com/dlang/druntime/pull/1792
[3]: http://dconf.org/2017/talks/cojocaru.html