Den 13. apr. 2012 02.46 skrev Richard O'Keefe <span dir="ltr"><<a href="mailto:ok@cs.otago.ac.nz">ok@cs.otago.ac.nz</a>></span>:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
On 13/04/2012, at 11:51 AM, Erik Søe Sørensen wrote:<br>
<br>
> <EEP-pattern_test_operator.md><br>
<br>
(0) Congratulations and thanks for providing a reference<br>
    implementation.<br></blockquote><div>Thanks... the write-up was the more time-consuming part, and I appear to have botched that job ;-)<br> <br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

(1) PLEASE don't take the binary ~ operator; we need<br>
    that for frames, and we need frames URGENTLY.<br>
    The use of "~" is indeed backwards compatible<br>
    with respect to existing _code_ but not with<br>
    respect to existing _EEPS_.<br></blockquote><div>Which EEP in particular?  I can't seem to find any mention of using tilde - except on the mailing list. <br><br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

(2) I don't understand why it is not sufficient to<br>
    allow <pattern> = <guard expression> as a guard<br>
    expression.  That would be a simple change that<br>
    would increase the simplicity of the language<br>
    by removing a constraint; this change makes the<br>
    language *more* complex.<br>
<br>
    The argument near the end I find unconvincing in<br>
    the extreme: = isn't *supposed* to return booleans,<br>
    and guards should never have had 'and' 'or' 'andalso'<br>
    or 'orelse' in the first place but should have nested<br>
    the existing ',' and ';'.  Guard tests drive control<br>
    NOT by returning true or false but by SUCCEEDING or<br>
    FAILING, and that's *exactly* what = does.<br></blockquote><div><br>Guards drive control based on whether they evaluate to true or (fail / evaluate to something else).<br>Try this:<br>  F = fun(X) -> case X of Y when Y -> yes; _ -> no end end.<br>
  [F(true), F(false), F(other)].<br>I get [yes, no, no] - consistent with the "true or not" test; the shell and the compiler agree on this.<br>This semantics is also simple in that guard functions behave the same whether they occur within a guard or elsewhere.<br>
Why should '=' behave any differently?<br><br><br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
    It is already a readability problem that = can appear<br>
    deeply nested inside expressions, and the proposed<br>
    inverted ~ worsens this amazingly:  not only may<br>
    bindings be hidden deep inside surprising places,<br>
    they may be hidden in two opposing orders with<br>
    subtly different semantics.<br>
<br>
(3) Since we have the syntax <pattern> = <expression>,<br>
    requiring <expression> ~ <pattern> is very nearly<br>
    unforgivable.  The EEP confused me enormously<br>
    until I got my head around this inversion.<br></blockquote><div> </div><div>I'm sorry, but I find the other way around unreadable.<br>The expression-before-pattern form reads better aloud: "if E matches P..."<br>
Also, most of Erlang has left-to-right evaluation - 'case', ',', 'when', 'andalso', 'orelse', 'try', and clause lists all follow this.<br><br><br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

(4) case ... of<br>
      X  when  X ~ {ok,A}; X ~ [okay,A} -> ...A...<br>
    end<br>
<br>
    In "[okay,A}", is "[" a typo for "{"<br>
    or is "}" a typo for "]"?</blockquote><div>The former - sorry, I hadn't noticed this. (The latter would also work, though, but wasn't the intention.)<br> <br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
  This can be handled<br>
    by a proposal I _think_ there is an EEP for to <br></blockquote><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
    allow<br>
<br>
        case ...<br>
          of {ok,A}<br>
           ; {okay,A} -> ... A ...<br>
        end<br></blockquote><div>At a quick glance, the closest one appears to be "unnesting cases". That one doesn't allow that syntax, though; it's a different extension.<br> </div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

<br>
    the generalisation being that<br>
        <pattern> [when <guard>]<br>
    is replaced by<br>
        <pattern> [when <guard>] {; <pattern> [when <guard>]}...<br>
<br>
    That may have been one of the EEPs I could not write up<br>
    because there is no serious definition of .md syntax and<br>
    semantics.<br></blockquote><div>It probably is. <br><br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
    case E0 ~ P of true -> E1; false -> E2 end<br></blockquote><div>was part of a concocted counter-example.<br><br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

    seems like a strange way to write<br>
<br>
        case E0<br>
          of P -> E1<br>
           ; _ -> E2<br>
        end<br>
<br>
(5) The "bindings are only accessible" part is not specified<br>
    precisely.  In particular, consider<br>
<br>
        (X ~ {foo,A} orelse X ~ {bar,A} orelse X ~ {ugh,A})<br>
        andalso ... A ...<br>
<br>
    Is some binding for A accessible after andalso, and if<br>
    not, why not?</blockquote><div>Not as specified, no; the first operand of the 'andalso' is an 'orelse' expression.<br>You're right that if the third rule is generalized (to cover the case where all guards connected by ';' bind a variable), then the first rule should be too (to cover the case where a number of subexpressions connected by 'orelse' bind a variable). I believe I felt that stating rules for handling orelse/andalso in general would make the spec unnecessarily complex (from a "persuading people that this is a good idea which is simple to implement" viewpoint), and decided to postpone that part.<br>
(I have handled the general case in another language, though.)<br> </div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">  If it were written<br>
<br>
        case X<br>
          of {foo,A}<br>
           ; {bar,A}<br>
           ; {ugh,A} -> ... A ...<br>
        end<br>
<br>
    the variables available at the arrow would clearly and<br>
    simply be the intersection of the variables available<br>
    after each pattern/guard.<br></blockquote><div>Agreed.<br> <br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
(6) The EEP has very few examples that cannot be done as well<br>
    or better using Pattern = Guard_Expr in a guard and/or<br>
    the generalised case, both of which make disjunction of<br>
    pattern/guards readily expressible.  The main novelty<br>
    seems to be "anything but this".<br>
<br>
    For example,<br>
<br>
        receive<br>
           X when (      F = {'$gen_cast',_} = X<br>
                  orelse F = {'$gen_call',_} = X<br>
                  orelse F = ok<br>
                  ) andalso F = ok -><br>
<br>
<br>
    neatly handles the "not a {'$gen_cast',_} or {'$gen_call',_}"<br>
    example, and all it needs is to allow Pattern = Expression in<br>
    a context where people already expect it to be allowed.<br>
<br>
    In general, I must say that I have learned over the painful<br>
    years to loathe and dread "anything but <this>" matches in<br>
    whatever language they are found.  If Erlang makes it hard<br>
    to express such proven bug-breeder, all the better for<br>
    Erlang.<br>
<br>
    The lack of negative patterns is a positive BENEFIT of the<br>
    way Erlang is now; sabotaging this aspect of Erlang would be<br>
    done at our peril.<br></blockquote><div>Fair enough; I can't say that I regard the negation aspect as a particularly strong selling point.<br><br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

    All things considered, I think that the sharper the distinction<br>
    between pattern/guards and expressions the better; it helps to<br>
    keep Erlang readable in a way that anything-goes-anywhere doesn't.<br></blockquote><div>We already have "some expressions may occur in guards".<br>And you propose allowing "pattern matching may occur in guards" yourself.<br>
So it must be the "pattern matching may occur in non-guard expressions" part that buggers you (right?).<br>Now, that is already allowed as well - just in the less syntactically convenient form of "case E of P -> true; _ -> false end".  I haven't seen anyone using such a construct as an operand for 'andalso' or similar - because that would certainly qualify as unreadable - but I fail to see why pattern-based branching could not be used in this light-weight way, instead of always having to occur in more verbose constructs.<br>
 <br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
(7) We keep on getting odd limited or dangerous proposals for<br>
    things that are neatly and simply solved by abstract patterns.<br>
    For example,<br>
<br>
        #int_point(X, Y)<br>
            when is_integer(X), is_integer(Y)<br>
              -> {X, Y}.<br>
<br>
        #two_int_points(X = #int_point(_,_),<br>
                        Y = #int_point(_,_))<br>
              -> {X, Y}.<br>
<br>
    Yes, the abstract patterns EEP notes that allowing patterns in<br>
    guards is a prerequisite.  That mean we ALREADY have an EEP that<br>
    proposes patterns in guards.  But that meant the existing =<br>
    with the existing semantics; just a restriction removed.</blockquote><div>Except that it isn't that compatible with existing semantics.<br> <br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

    This new proposal is far more elaborate than the abstract<br>
    patterns EEP requires, far more confusing, and far more dangerous.<br>
    Once we have abstract patterns, there would be little or no<br>
    reason to _use_ the inverted ~ in actual source code.<br></blockquote><div>That could be true. <br><br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

(8) The thing I don't get a feeling for is how _much_ of a problem<br>
    this EEP solves.  When similar things have come up in the past<br>
    I have asked for concrete examples, and have generally been<br>
    able to show that it is possible to rewrite the real code in<br>
    existing Erlang with good clarity without new features.<br>
    (Or with abstract patterns as the only new feature.)<br></blockquote><div> </div></div>I'd very much like to hear others' opinions: how can we add a feature like this (or like EEP14, which is apparently the other candidate) in a way that fits well into the existing language and feels natural and not "confusing" or "inverted" (or even "dangerous")?<br>
<br>(It may well be that the most peaceful way ahead is for me to make the pattern test operator work internally in the compiler, without any source syntax form, and then the implementation of EEP 29 can proceed... :-) )<br>
<br>/Erik<br>