<div dir="ltr"><div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Mon, Sep 17, 2018 at 4:41 AM Robert Virding <<a href="mailto:rvirding@gmail.com">rvirding@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div>Sorry I have missed this until now. Isn't this similar to the elixir 'with ... do ... error ... end' construct? At least in trying to flatten potential nested cases? Though it seems to be more specific in how it handles the return values.</div><div><br></div><div>Robert</div><br></div></blockquote><div><br></div><div>There are a few important distinctions. See <a href="https://github.com/erlang/eep/blob/master/eeps/eep-0049.md#elixir-like-patterns-in-with">https://github.com/erlang/eep/blob/master/eeps/eep-0049.md#elixir-like-patterns-in-with</a> for the full rationale compared to Elixir's <i>with </i>construct.</div><div><br></div><div> The TL:DR; is that their stuff is more general, but contains some ambiguities that makes it weaker for error handling specifically. For example in:<br></div><div>
<pre><code>-spec fetch() -> {ok, iodata()}.
fetch() ->
begin
{ok, B = <<_/binary>>} <- f(),
true <- validate(B),
{ok, sanitize(B)}
end.
</code></pre>
<p>If the value returned from <code>f()</code> is a list (a socket using <code>list</code> instead of <code>binary</code> as an option), the
expression will return early, the <code>fetch()</code> function will still return
<code>{ok, iodata()}</code> but you couldn’t know as a caller whether it is the
transformed data or non-matching content. This could represent a major security risk allowing to bypass sanitization. The only way to fix it is to have the 'else' block that contain all expected possible erroneous values to make sure the "unexpected good but non-matching values" do cause a failure while "actual expected errors" get returned, which is tedious. <br></p><p>This problem is impossible with <br></p><p></p><p>
</p><pre><code>-spec fetch() -> {ok, iodata()}.
fetch() ->
begin
B = <<_/binary>> <~ f(),
_ <~ validate(B), % returns ok if valid
{ok, sanitize(B)}
end.</code></pre>
</div><div>Due to the stricter matching rules on correct results.</div><div><br></div><div>I suspect Elixir folks don't run into that problem too often because their pattern matching rules re-bind variables by default, so most cases that could be "accidental non-matches" never show up, or otherwise mainly use the pattern for side-effectful calls where they don't care for the good value being returned.<br>
</div></div></div></div>