Experimental
TryExperimental.Result — TypeTryExperimental.Result{T,E}A super type of Ok{<:T}, Err{<:E}, and ConcreteResult{T,E}.
See also: Try.Ok, Try.Err, ConcreteResult.
Extended help
Examples
Consider creating an API tryparse(T, input) -> result. To simplify the example, let us define the implementation using Base.tryparse:
using Try
using TryExperimental
using TryExperimental: Result
struct InvalidCharError <: Exception end
struct EndOfBufferError <: Exception end
function __tryparse__(::Type{Int}, str::AbstractString)
isempty(str) && return Err(EndOfBufferError())
Ok(@something(Base.tryparse(Int, str), return Err(InvalidCharError())))
end
nothing # hide
# outputwhere __tryparse__ is an overload-only API. If it is decided that the call API tryparse should have a limited set of failure modes, it can be enforced by the return value conversion to a Result type.
tryparse(T, input)::Result{T,Union{InvalidCharError,EndOfBufferError}} =
__tryparse__(T, input)
nothing # hide
# outputjulia> tryparse(Int, "111")
Try.Ok: 111
julia> tryparse(Int, "one")
Try.Err: InvalidCharError()Discussion
Currently, Result is defined as
Result{T,E} = Union{ConcreteResult{T,E},Ok{<:T},Err{<:E}}although there are other possible definitions:
Result{T,E} = Union{ConcreteResult{<:T,<:E},Ok{<:T},Err{<:E}}
Result{T,E} = Union{ConcreteResult{T,E},Ok{T},Err{E}}
Result{T,E} = AbstractResult{<:T, <:E}
Result = AbstractResultThe current definition of Result may look strange since the type parameters are invariant for ConcreteResult and variant for Ok and Err. This is chosen given the expectation that Union{Ok,Err} users likely to prefer to let the compiler extra opportunities to perform pass-dependent optimizations while ConcreteResult users likely to prefer control the exact return type. The definition of Result allows these usages simultaneously.
This let __tryparse__ implementers opt-in ConcreteResult by simply converting their return value to a ConcreteResult:
function __tryparse__(T::Type, io::MyIO)::ConcreteResult{T,InvalidCharError}
...
endThis example also demonstrates that ConcreteResult{T,InvalidCharError} can automatically be converted to Result{T,Union{InvalidCharError,EndOfBufferError}}.
As explained above, Result{T,E} seems to have nice properties. However, it is not clear if it works in practice. This is why Result is provided from TryExperimental but not from Try. For example, ConcreteResult may not be useful in practice. If ConcreteResult is dropped, it may be a good idea to define
Result{T,E} = Union{Ok{T},Err{E}}so that the users can explicitly manipulate the variance of each parameters.
TryExperimental.ConcreteResult — TypeTryExperimental.ConcreteResult{T,E}Similar to Union{Ok{T},Err{E}} but it is a concrete type.
Examples
julia> using Try
julia> using TryExperimental: ConcreteResult
julia> convert(ConcreteResult{Symbol,Union{BoundsError,DomainError}}, Ok(:a))
TryExperimental.ConcreteResult (Ok): :aCustomizing short-circuit evaluation
TryExperimental.branch — FunctionTryExperiment.branch(result) -> Continue(result)
TryExperiment.branch(result) -> Break(result)branch implements a short-circuiting evaluation API. It must return a Continue or a Break.
TryExperimental.Break — TypeTryExperimental.Break(result)TryExperimental.Continue — TypeTryExperimental.Continue(result)TryExperimental.resultof — FunctionTryExperimental.resultof(branch) -> result
TryExperimental.resultof(branch::Continue{<:Ok}) -> result::Ok
TryExperimental.resultof(branch::Break{<:Err}) -> result::Err
TryExperimental.resultof(branch::Continue{<:Some}) -> result::Some
TryExperimental.resultof(branch::Break{Nothing}) -> nothingTryExperimental.valueof — FunctionTryExperimental.valueof(branch) -> value
TryExperimental.valueof(branch::Continue{Ok{T}}) -> value::T
TryExperimental.valueof(branch::Break{Err{T}}) -> value::T
TryExperimental.valueof(branch::Continue{Some{T}}) -> value::T
TryExperimental.valueof(branch::Break{Nothing}) -> nothing"Tryable" function
TryExperimental.@tryable — MacroTryExperimental.@tryable nameCreate a function that can be called without causing a MethodError.
Note that Ok and Err values can be used in arbitrary functions. @tryablefn is simply a shorthand for defining a fallback implementation
fn(args...; kwargs...) = Err(NotImplementedError(fn, args, values(kwargs)))(and auxiliary methods like istryable) to help the "Easier to ask for forgiveness than permission" (EAFP) approach.
See also: istryable.
Examples
julia> using TryExperimental: @tryable
julia> @tryable fn;
julia> fn
fn (tryable function with 1 method)
julia> fn(1)
Try.Err: Not Implemented: fn(1)TryExperimental.istryable — FunctionTry.istryable(callable::Any) -> bool::BoolCheck if a callable can be called without causing a MethodError.
See also: @tryable.
Examples
julia> using TryExperimental: @tryable, istryable
julia> @tryable fn;
julia> istryable(fn)
true
julia> istryable(identity)
false