update syntax for try and nullable unwrapping #285

Closed
andrewrk opened this Issue Mar 26, 2017 · 6 comments

Comments

Projects
None yet
3 participants
@andrewrk
Member

andrewrk commented Mar 26, 2017

try (foo()) |payload| {

} else |err| {

}
test (bar()) |payload| {

} else {

}
fn foo() -> %i32 {
    // ...
}
fn bar() -> ?i32 {
    // ...
}

@andrewrk andrewrk added this to the 0.1.0 milestone Mar 26, 2017

@raulgrell

This comment has been minimized.

Show comment
Hide comment
@raulgrell

raulgrell Mar 28, 2017

Contributor

I like the syntax, it's very consistent with the rest of the language. How would you feel about a finally block in case you want to return from the try/else?

Test seems like a bad name for the null test. Satus quo allows it already:

    if ( const payload ?= bar() ) {
        use(payload)
    } else {
        // no payload
    }

With #217 we can create an equivalent error-assignment operator

    if ( const payload %= foo() ) {
        use(payload)
    } else |err| {
        use(err)
    }

The only thing that feels off is the sudden appearence of that |err| in the if statement. I'd also like to be able to do something like iterating through a linked list:

    const Node = struct { next: ?&Node };
    var maybe_ptr: ?&Node

    while ( const ptr ?= maybe_ptr ) {
        maybe_ptr = ptr.next
    } else {
         // execute once first time ptr is null, never if breaking out of loop.
    }
Contributor

raulgrell commented Mar 28, 2017

I like the syntax, it's very consistent with the rest of the language. How would you feel about a finally block in case you want to return from the try/else?

Test seems like a bad name for the null test. Satus quo allows it already:

    if ( const payload ?= bar() ) {
        use(payload)
    } else {
        // no payload
    }

With #217 we can create an equivalent error-assignment operator

    if ( const payload %= foo() ) {
        use(payload)
    } else |err| {
        use(err)
    }

The only thing that feels off is the sudden appearence of that |err| in the if statement. I'd also like to be able to do something like iterating through a linked list:

    const Node = struct { next: ?&Node };
    var maybe_ptr: ?&Node

    while ( const ptr ?= maybe_ptr ) {
        maybe_ptr = ptr.next
    } else {
         // execute once first time ptr is null, never if breaking out of loop.
    }
@andrewrk

This comment has been minimized.

Show comment
Hide comment
@andrewrk

andrewrk Mar 28, 2017

Member

How would you feel about a finally block in case you want to return from the try/else?

How would this work? Wouldn't the finally block be the same as putting an expression after the entire construct?

try (foo()) |payload| {

} else |err| {

}
// I got your "finally" right here
doSomethingFinally();

Another way to write the linked list looping code:

    while (true) {
        const ptr = maybe_ptr ?? break;
    }
Member

andrewrk commented Mar 28, 2017

How would you feel about a finally block in case you want to return from the try/else?

How would this work? Wouldn't the finally block be the same as putting an expression after the entire construct?

try (foo()) |payload| {

} else |err| {

}
// I got your "finally" right here
doSomethingFinally();

Another way to write the linked list looping code:

    while (true) {
        const ptr = maybe_ptr ?? break;
    }
@thejoshwolfe

This comment has been minimized.

Show comment
Hide comment
@thejoshwolfe

thejoshwolfe Mar 28, 2017

Member

How would you feel about a finally block in case you want to return from the try/else?

defer is intended to generalize and eliminate the need for finally.

Member

thejoshwolfe commented Mar 28, 2017

How would you feel about a finally block in case you want to return from the try/else?

defer is intended to generalize and eliminate the need for finally.

@raulgrell

This comment has been minimized.

Show comment
Hide comment
@raulgrell

raulgrell Mar 28, 2017

Contributor

How would this work? Wouldn't the finally block be the same as putting an expression after the entire construct?

Not really, since if you wanted to return from within the blocks, whatever came after the try won't run because the function has returned already. But @thejoshwolfe is right when he says defer generalizes it.

fn bar() -> %T {
    defer {
         // Here's my stupid finally block
    }
    try (foo()) |payload| {
        // do something to/with payload
        return payload;
    } else |err| {
        // do something to/with err
        return err
    }
    // or would you not be able to return from a try statement?
    unreachable;
}
Contributor

raulgrell commented Mar 28, 2017

How would this work? Wouldn't the finally block be the same as putting an expression after the entire construct?

Not really, since if you wanted to return from within the blocks, whatever came after the try won't run because the function has returned already. But @thejoshwolfe is right when he says defer generalizes it.

fn bar() -> %T {
    defer {
         // Here's my stupid finally block
    }
    try (foo()) |payload| {
        // do something to/with payload
        return payload;
    } else |err| {
        // do something to/with err
        return err
    }
    // or would you not be able to return from a try statement?
    unreachable;
}
@andrewrk

This comment has been minimized.

Show comment
Hide comment
@andrewrk

andrewrk Mar 28, 2017

Member

// or would you not be able to return from a try statement?

unlike other languages, there's nothing special about the try block, other than that the payload is in scope. The thing that you're "trying" is contained in the parentheses (foo() in this case) and that's where you could not return. For example, this would be an error:

try (return foo) { ... }

This would be error: expected error union type, found 'unreachable'.

Member

andrewrk commented Mar 28, 2017

// or would you not be able to return from a try statement?

unlike other languages, there's nothing special about the try block, other than that the payload is in scope. The thing that you're "trying" is contained in the parentheses (foo() in this case) and that's where you could not return. For example, this would be an error:

try (return foo) { ... }

This would be error: expected error union type, found 'unreachable'.

@raulgrell

This comment has been minimized.

Show comment
Hide comment
@raulgrell

raulgrell Mar 28, 2017

Contributor

In any case, I retract any objections

Contributor

raulgrell commented Mar 28, 2017

In any case, I retract any objections

@andrewrk andrewrk closed this in 0cce115 Apr 21, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment