April 18, 2020
On 2020-04-17 13:28, Mike Parker wrote:
> This is the discussion thread for the Final Review of DIP 1029, "Add throw as Function Attribute":
> 
> https://github.com/dlang/DIPs/blob/9db80ddadcf5a220958ddcfec14b9c71cdb43d1c/DIPs/DIP1029.md 

I would like to see the "throw" keyword being used as an attribute to implement something like "Zero-overhead deterministic exceptions: Throwing values" [1].

I imagine it looking something like this:

enum CopyError
{
    permissionDenied
}

void copy(string src, string dest) throw(CopyError)
{
    throw CopyError.permissionDenied;
}

void main()
{
    try
        copy("foo", "bar");
    catch (CopyError e)
        writeln(e);
}

Which would be lowered to something like the equivalent of the following code:

struct Result(Value, Error)
{
    bool isValue;
    union
    {
        Value value;
        Error error;
    }

    this(Value value)
    {
        this.value = value;
        isValue = true;
    }

    this(Error errro)
    {
        this.error = error;
        isValue = true;
    }
}

Result!(void, CopyError) copy(string src, string dest)
{
    return Result!(void, CopyError)(CopyError.permissionDenied);
}

void main()
{
    auto result = copy("foo", "bar");

    if (!result.isValue)
        goto L1;
    L1:
        writeln(result.error);
}


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

-- 
/Jacob Carlborg
April 18, 2020
On Saturday, 18 April 2020 at 12:03:46 UTC, Jacob Carlborg wrote:
> Result!(void, CopyError) copy(string src, string dest)
> {
>     return Result!(void, CopyError)(CopyError.permissionDenied);
> }
>
> void main()
> {
>     auto result = copy("foo", "bar");
>
>     if (!result.isValue)
>         goto L1;
>     L1:
>         writeln(result.error);
> }

The big downside of this compared to exceptions is that you can forget to check the return value of `copy`, whereas exceptions cannot be ignored.

In Rust and C++, they have `#[must_use]` and `[[nodiscard]]` respectively to force the programmer to check the return value. Without something equivalent in D, using algebraic data types for error handling is not really a viable approach.
April 18, 2020
On Saturday, 18 April 2020 at 14:02:46 UTC, Paul Backus wrote:
> On Saturday, 18 April 2020 at 12:03:46 UTC, Jacob Carlborg wrote:
>> void main()
>> {
>>     auto result = copy("foo", "bar");
>>
>>     if (!result.isValue)
>>         goto L1;
>>     L1:
>>         writeln(result.error);
>> }
>
> The big downside of this compared to exceptions is that you can forget to check the return value of `copy`, whereas exceptions cannot be ignored.

That part was only the lowered code.


April 18, 2020
On Saturday, 18 April 2020 at 12:03:46 UTC, Jacob Carlborg wrote:
> On 2020-04-17 13:28, Mike Parker wrote:
>> This is the discussion thread for the Final Review of DIP 1029, "Add throw as Function Attribute":
>> 
>> https://github.com/dlang/DIPs/blob/9db80ddadcf5a220958ddcfec14b9c71cdb43d1c/DIPs/DIP1029.md
>
> I would like to see the "throw" keyword being used as an attribute to implement something like "Zero-overhead deterministic exceptions: Throwing values" [1].
>
> I imagine it looking something like this:
>
> enum CopyError
> {
>     permissionDenied
> }
>
> void copy(string src, string dest) throw(CopyError)
> {
>     throw CopyError.permissionDenied;
> }
>
> void main()
> {
>     try
>         copy("foo", "bar");
>     catch (CopyError e)
>         writeln(e);
> }
>
> Which would be lowered to something like the equivalent of the following code:

You could have the caller pass an alternate return address to the callee. So...

void copy(string src, string dest, void* err)
{
    if (somethingbad) { EAX = errorcode; RET (to) err; } ***
}

void main()
{
    auto result = copy("foo", "bar", &L1);

    return;

    L1: writeln("Oh noes!");
}

*** So all the callee has to do is poke the alternate return address into the stack and RET as normal. (On x86 at least).


May 05, 2020
On Friday, 17 April 2020 at 11:28:05 UTC, Mike Parker wrote:
> This is the discussion thread for the Final Review of DIP 1029, "Add throw as Function Attribute":

On Tuesday, 5 May 2020 at 14:39:24 UTC, Petar Kirov [ZombineDev] wrote:
>
> Otherwise, I'd say that the best solution, which I think Andrei agreed with [1] is `attribute(true)` and `attribute(false)` or more generally: `attribute(boolExpr)`.
>
> [1]: https://forum.dlang.org/post/mknspb$1dgl$1@digitalmars.com

Good digging! I agree with you and Andrei, but using template syntax would be an additional improvement, it's not about saving one char, but avoiding matching () in the common case.

attribute!true
attribute!false
attribute!(boolExpr)

May 05, 2020
On Tuesday, 5 May 2020 at 15:30:38 UTC, Tove wrote:
> Good digging! I agree with you and Andrei, but using template syntax would be an additional improvement, it's not about saving one char, but avoiding matching () in the common case.
>
> attribute!true
> attribute!false
> attribute!(boolExpr)

It seems more confusing to me to use template syntax for something that isn't a template.

We already use parentheses for stuff like `extern(C)`. Using them for function attributes is a natural extension of that.
May 05, 2020
On Tuesday, 5 May 2020 at 15:55:30 UTC, Paul Backus wrote:
> On Tuesday, 5 May 2020 at 15:30:38 UTC, Tove wrote:
>> Good digging! I agree with you and Andrei, but using template syntax would be an additional improvement, it's not about saving one char, but avoiding matching () in the common case.
>>
>> attribute!true
>> attribute!false
>> attribute!(boolExpr)
>
> It seems more confusing to me to use template syntax for something that isn't a template.
>
> We already use parentheses for stuff like `extern(C)`. Using them for function attributes is a natural extension of that.

If we turn the existing function attributes into compiler recognized UDAs, the template version is one char shorter:

    version (A)
    {
        struct nogc { bool enabled; }
        void foo() @(nogc(true)) { }
    }
    else version (B)
    {
        struct nogc(bool enabled) { }
        void foo() @(nogc!true) { }
    }


;)
May 05, 2020
On Tuesday, 5 May 2020 at 15:55:30 UTC, Paul Backus wrote:
> On Tuesday, 5 May 2020 at 15:30:38 UTC, Tove wrote:
>> Good digging! I agree with you and Andrei, but using template syntax would be an additional improvement, it's not about saving one char, but avoiding matching () in the common case.
>>
>> attribute!true
>> attribute!false
>> attribute!(boolExpr)
>
> It seems more confusing to me to use template syntax for something that isn't a template.
>
> We already use parentheses for stuff like `extern(C)`. Using them for function attributes is a natural extension of that.

It's not a function either and extern!C would be fine with me.

IIRC `extern(C)` existed long before the single argument template syntax. It may appear a minor feature, but I miss it a lot when forced to use other languages.

May 05, 2020
On Saturday, 18 April 2020 at 16:28:59 UTC, NaN wrote:
> You could have the caller pass an alternate return address to the callee. So...
>
> void copy(string src, string dest, void* err)
> {
>     if (somethingbad) { EAX = errorcode; RET (to) err; } ***
> }
>
> void main()
> {
>     auto result = copy("foo", "bar", &L1);
>
>     return;
>
>     L1: writeln("Oh noes!");
> }
>
> *** So all the callee has to do is poke the alternate return address into the stack and RET as normal. (On x86 at least).

A paper describing the idea.

https://dl.acm.org/doi/pdf/10.1145/1016848.1016864

I thought there was a more practical one, but only found this.
1 2
Next ›   Last »