March 27, 2020
On Fri, Mar 27, 2020 at 10:26:11PM +0000, NaN via Digitalmars-d wrote:
> On Friday, 27 March 2020 at 20:16:19 UTC, H. S. Teoh wrote:
[...]
> > Honestly, I think cheap Exceptions could be done transparently of user code, for the most part.  Instead of using libunwind or equivalent, for example, just change the ABI to propagate an out-of-band error indicator that, say in a register or something that gets checked by the caller and branches to the function's exit block if set.
> 
> Why not just pass the address of the error handler into the callee? So instead of
> 
> foo()
> if (R12) goto i_see_dead_people;
> 
> void foo()
> {
>     if (zombies) { R12 = err; return; }
> }
> 
> you do...
> 
> R12 = &i_see_dead_people
> foo();
> 
> void foo()
> {
>     if (zombies) { return to R12; }
> }
> 
> On x86 at least you could just poke the alternate return address into the stack and do RET as you would for normal return. So in the non-error path it's a single LEA instruction, vs a compare and conditional branch if using an extra return value.

That would work too, I guess.

The point is, these are all implementation details that can be implemented in a way that's transparent to user code.  It doesn't have to be libunwind with its associated overhead that Walter did not like.


T

-- 
"Maybe" is a strange word.  When mom or dad says it it means "yes", but when my big brothers say it it means "no"! -- PJ jr.
March 27, 2020
On Friday, 27 March 2020 at 22:47:36 UTC, H. S. Teoh wrote:
> The point is, these are all implementation details that can be implemented in a way that's transparent to user code.  It doesn't have to be libunwind with its associated overhead that Walter did not like.


It used to be this way! D had a custom exception mechanism (on linux, on Windows it used SEH which works very well) that was quite lightweight, but it got killed in the name of C++ compatibility :(
March 27, 2020
On Fri, Mar 27, 2020 at 11:40:35PM +0000, Adam D. Ruppe via Digitalmars-d wrote:
> On Friday, 27 March 2020 at 22:47:36 UTC, H. S. Teoh wrote:
> > The point is, these are all implementation details that can be implemented in a way that's transparent to user code.  It doesn't have to be libunwind with its associated overhead that Walter did not like.
> 
> It used to be this way! D had a custom exception mechanism (on linux, on Windows it used SEH which works very well) that was quite lightweight, but it got killed in the name of C++ compatibility :(

Hmm.  Then maybe we should make this an optional thing so that projects that don't need C++ compatibility don't have to suffer for it?

Either that, or do the translation at the C++/D boundary only, instead of throughout the entire call stack. Basically:

1) A D function declared extern(C++) would throw a libunwind compatible
exception in its exit block if it had caught a D-specific exception.

2) A D function that calls an extern(C++) function would insert a libunwind-compatible catch block that translates any thrown C++ exception into the D-specific implementation, then continues propagating it as before (including to any user-defined catch blocks if the user wrote one in the function).

So we only need to pay if C++ compatibility was actually used, rather than pessimize all D code just on the off-chance that C++ compatibility *might* be required.


T

-- 
People say I'm indecisive, but I'm not sure about that. -- YHL, CONLANG
March 28, 2020
On Friday, 27 March 2020 at 22:34:40 UTC, Mike Parker wrote:
> The D1/D2 split was much more impactful.

What, specifically, was it?

D2 was literally just an arbitrary point release in an ongoing evolution. String literals becoming invariant, for example, happened at 2.006, which was probably the biggest breaking change outside the phobos library. I recall that being a pretty invasive change, but the most annoying to me as i remember was actually renaming in phobos, like stripl to stripLeft and such which was spread over several releases.

I also recall some commercial users having major problems with the change to slices - the array stomping protection modification, which was a silent runtime breaking change.

But it will be worth looking at exactly what it was and why it bothered people. There's been breaking changes before and after the D2 name too, and the D2 name itself didn't actually break anything. So bringing it up without a specific policy isn't helpful.

> There was also this quote from Walter a few years back:

His memory is as faulty as anyone else's.
March 28, 2020
On Friday, 27 March 2020 at 15:56:40 UTC, Steven Schveighoffer wrote:
> There have been a lot of this pattern happening:
>
> 1. We need to add feature X, to fix problem Y.
> 2. This will break ALL CODE IN EXISTENCE
> 3. OK, cancel the fix, we'll just live with it.


Yes, but not because we want to break things, but because we are breaking things.

The preview switches are great, but can we get a grouped feature set for release.

It is critical that the existing libraries can be utilized with newer language versions (at least for a time).

Stationary is not an option, but a good upgrade which does not compromise the ecosystem is vital.
March 28, 2020
On 28/03/2020 5:41 PM, Jesse Phillips wrote:
> On Friday, 27 March 2020 at 15:56:40 UTC, Steven Schveighoffer wrote:
>> There have been a lot of this pattern happening:
>>
>> 1. We need to add feature X, to fix problem Y.
>> 2. This will break ALL CODE IN EXISTENCE
>> 3. OK, cancel the fix, we'll just live with it.
> 
> 
> Yes, but not because we want to break things, but because we are breaking things.
> 
> The preview switches are great, but can we get a grouped feature set for release.
> 
> It is critical that the existing libraries can be utilized with newer language versions (at least for a time).
> 
> Stationary is not an option, but a good upgrade which does not compromise the ecosystem is vital.

I have said this before, D3 should be a preview switch which turns on all the others.

All D2 code should be compilable with D3, but not all D3 should be compilable as D2.

dmd3 could literally be the preview switch turned on permanently.
March 28, 2020
On 2020-03-28 01:53, Adam D. Ruppe wrote: > D2 was literally just an arbitrary point release in an ongoing
> evolution. 

Yes.

> String literals becoming invariant, for example, happened at 2.006, which was probably the biggest breaking change outside the phobos library. I recall that being a pretty invasive change

String literals have always been placed in read-only sections on Posix. In D1, even if the compiler did let you modify string literals it would crash at runtime. Perhaps it was only a problem on Windows?

-- 
/Jacob Carlborg
March 28, 2020
On 2020-03-27 18:32, H. S. Teoh wrote:

> What about supporting multiple versions of the language simultaneously

Rust is already doing that, they call it "editions", and it's a much younger language than D and should have less code to worry about.

Each of your dependencies can be built using different editions and it all works together.

-- 
/Jacob Carlborg
March 28, 2020
On 2020-03-28 00:40, Adam D. Ruppe wrote:

> It used to be this way! D had a custom exception mechanism (on linux, on Windows it used SEH which works very well) that was quite lightweight, but it got killed in the name of C++ compatibility :(

Funny thing. There's a C++ proposal by Herb Sutter, "Zero-overhead deterministic exceptions: Throwing values" [1]. Which more or less lowers the current syntax used for exception to something similar to return codes.

Existing C++ code like this (which can not afford to use table based exceptions):

expected<int, errc> safe_divide(int i, int j) {
    if(j==0)
        return unexpected(arithmetic_errc::divide_by_zero);
    if(i==INT_MIN&&j==-1)
        return unexpected(arithmetic_errc::integer_divide_overflows);
    if(i%j!=0)
        return unexpected(arithmetic_errc::not_integer_division);
    else return i / j;
}

expected<double, errc> caller(double i, double j, double k) {
    auto q = safe_divide(j, k);
    if (q) return i + *q;
    else return q;
}

Can with the new proposal be expressed like this:

int safe_divide(int i, int j) throws {
    if(j==0)
        throw arithmetic_errc::divide_by_zero;
    if(i==INT_MIN&&j==-1)
        throw arithmetic_errc::integer_divide_overflows;
    if(i%j!=0)
        throw arithmetic_errc::not_integer_division;
    else return i / j;
}

double caller(double i, double j, double k) throws {
    return i + safe_divide(j, k);
}

Which are more or less lowered to code similar as the original example.

If we want to stay compatible with C++ exception handling, we need to implement this :). Although we currently don't support any other features added after C++98.

[1] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0709r0.pdf

-- 
/Jacob Carlborg
March 28, 2020
On 2020-03-27 21:25, H. S. Teoh wrote:

> There's already dfix.  Does it not work well enough?  What are the
> issues the prevent us from using it in general?

It's not good enough. It's not based on the DMD frontend, it uses its own parser. It doesn't do any semantic analysis. As long as the DMD frontend is not used, it will always play catch up and will most likely never do semantic analysis.

It's also not an official tool.

-- 
/Jacob Carlborg