[eeps] EEP 49: Value-Based Error Handling Mechanisms
Martin Bjorklund
mbj@REDACTED
Wed Dec 5 08:50:45 CET 2018
Hi,
Michael Truog <mjtruog@REDACTED> wrote:
> I know this is a bit after most comments have occurred, but it seems
> ok since a decision hasn't been made yet. I like the change to the
> begin/end, even though it attaches some magic interpretation of an ok
> 2-tuple and an error 2-tuple.
I don't like it, for that particular reason.
Trying to make the begin/end change
> more complex to handle other return values for Success/Error
> conditions (perhaps by adding type specifications to the syntax)
> doesn't seem like a good direction
How about something like:
begin
{ok, A} =~ do_something(),
{true, B} =~ do_something_else(A),
ok =~ at_last(B)
end
where =~ means that if the RHS value doesn't match the LHS expression,
the RHS value is returned from the begin ... end expression.
So if do_something_else() above returns false, the begin ... end would
return false.
But even with this, I'm not sure the benefits are worth the added
complexity of the language.
/martin
> , so the begin/end change seems good
> as-is. The begin/end change in EEP 49 should also make the approach
> more efficient than the equivalent source code using functions,
> similar to what is described at
> https://github.com/erlang/eep/blob/master/eeps/eep-0049.md#obsoleting-messy-patterns
> because less data is required to accomplish the same control flow.
>
> If the begin/end change in EEP 49 is not acceptable for some reason,
> or if people prefer an approach with functions, I have two functions
> which I have found useful to avoid "the pointy-case statement" problem
> that EEP 49 addresses. They are eval/1 and accum/2, as shown below:
>
> -type state() :: any().
> -type eval_value() :: any().
>
> -spec accum(L :: list({any(),
> fun((any(), state()) ->
> {ok, state()} | {{error, any()},
> state()})}),
> State :: state()) ->
> {ok, state()} | {{error, any()}, state()}.
>
> accum([], State) ->
> {ok, State};
> accum([{Value, F} | L], State) ->
> case F(Value, State) of
> {ok, StateNew} ->
> accum(L, StateNew);
> {{error, _}, _} = Error ->
> Error
> end.
>
> -spec eval(L :: list({eval_value(),
> fun((eval_value()) -> {ok, any()} | {error,
> any()})})) ->
> tuple().
>
> eval(L) ->
> eval(L, []).
>
> eval([], Output) ->
> erlang:list_to_tuple([ok | lists:reverse(Output)]);
> eval([{Value, F} | L], Output) ->
> case F(Value) of
> {ok, ValueNew} ->
> eval(L, [ValueNew | Output]);
> {error, _} = Error ->
> Error
> end.
>
> These functions may be helpful in Erlang/OTP, in the absence of the
> EEP 49 begin/end change. With the EEP 49 begin/end change, they may
> help with backwards compatible source code but there doesn't seem like
> there should be any type-checking advantage (type-checking should be
> worse this way) or any advantage related to avoiding exceptions (i.e.,
> avoiding the need to catch exceptions that causes the function
> call-path to be impure). Both use a list of 2-tuples where the
> 2-tuple represents Value -> Function. The eval Function is arity 1
> and a success result is an ok tuple one larger than the size of the
> list (allowing a match on all results). The accum Function is arity 2
> to allow the accumulation of state data in the second argument, with
> the final state value getting returned in an ok 2-tuple with a
> success.
>
> These functions could easily be added to the Erlang/OTP lists module
> to try and guide people away from creating pointy-case statement
> structures in their functions (causing the columns in the source code
> to grow to become less readable and possibly causing more functions to
> be created than necessary to break-up the functionality). For
> handling functions that require more arguments, a tuple or list could
> be passed as the Value provided (similar to what is commonly done with
> init/1 functions used with OTP behaviours).
>
> Some use of these functions can be seen at:
> https://github.com/CloudI/CloudI/blob/ce54b4ae354b5633593fba6bf68f4eedfab7985c/src/lib/cloudi_core/src/cloudi_core_i_logger.erl#L813-L826
> https://github.com/CloudI/CloudI/blob/develop/src/lib/cloudi_core/src/cloudi_core_i_configuration.erl#L3299-L3319
>
> So, while I like the begin/end EEP 49 change, the accum/2 and eval/1
> functions described above may help the discussion further, as an
> alternative or additional change.
>
> Best Regards,
> Michael
>
> _______________________________________________
> eeps mailing list
> eeps@REDACTED
> http://erlang.org/mailman/listinfo/eeps
More information about the eeps
mailing list