iamed2 / ResultTypes.jl

A Result type for Julia—it's like Nullables for Exceptions
Other
94 stars 9 forks source link

Add at-try(x) macro #17

Closed kmsquire closed 4 years ago

kmsquire commented 4 years ago

This mimics the behavior of the macro of the same name in Rust.

Rust has actually moved away from this macro, now adding ? to the end of Result types instead. That option isn't available to Julia (unless, perhaps, Julia moves towards using ResultTypes by default.)

I really wanted to call this @?, but question marks are not valid identifiers (they're syntax). I also tried @/ (a ? without pressing shift, on US keyboards at least). But that looked funny, so I went with precedence.

One other Rust-like behavior that this assumes is that exceptions higher in the stack will be converted to different exceptions as the stack unwinds. This is not common in Julia code (because exceptions are usually thrown, so there's little need to convert them). An additional Result convert method was added to make this easier, but users will still need to add convert methods for converting between their own exception types.

Example from the tests:

using ResultTypes

struct BarError <: Exception end
struct FooError <: Exception end
Base.convert(::Type{FooError}, ::BarError) = FooError()

function isbar(x)::Result{Bool, BarError}
    x == "foo" && return BarError()
    return x == "bar"
end

function foo(x)::Result{Int, FooError}
    bar = @try isbar(x)
    return bar ? 42 : 13
end

foobar = foo("bar") # unwrap(foobar) === 42
foofoo = foo("foo") # unwrap_error(foofoo) === FooError()
football = foo("tball") # unwrap(football) === 13
codecov-io commented 4 years ago

Codecov Report

Merging #17 into master will not change coverage. The diff coverage is 100%.

Impacted file tree graph

@@          Coverage Diff          @@
##           master    #17   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files           1      1           
  Lines          29     38    +9     
=====================================
+ Hits           29     38    +9
Impacted Files Coverage Δ
src/ResultTypes.jl 100% <100%> (ø) :arrow_up:

Continue to review full report at Codecov.

Legend - Click here to learn more Δ = absolute <relative> (impact), ø = not affected, ? = missing data Powered by Codecov. Last update 24e0aa7...d488e1c. Read the comment docs.

iamed2 commented 4 years ago

Looks good, but here's an additional suggestion:

What about an optional second argument that is a replacement exception to return? This will prevent people from having to necessarily pirate exception conversions in some cases, while still adding the convenience of the compact early return syntax.

kmsquire commented 4 years ago

Okay, @iamed2, I added a version which takes an error as the second argument. Let me know what you think and if you want any changes.

kmsquire commented 4 years ago

I just realized that ! is the syntax for macro calls in rust (I've only dabbled in the language). Since we're not modifying our arguments here, I'm going to change this to @try.

kmsquire commented 4 years ago

... which of course doesn't work because try is a keyword... ( sigh )

kmsquire commented 4 years ago

Actually, I just learned that it is possible to define @try:

https://discourse.julialang.org/t/using-reserved-words-syntax-try-as-macro-names/34063

Will push that change again.

kmsquire commented 4 years ago

Ready for re-review.

kmsquire commented 4 years ago

Sorry, forgot that I was using an autoformatter. Will fix.

kmsquire commented 4 years ago

Should be good to go!

iamed2 commented 4 years ago

Thanks!