There are another different between assignment and _let_, a _let_ creates new fresh local variables (binding) while assignment is able to reuse an existing local variable.

Correct, the more precise analogy is not to _assignment_, but to _local variable declaration with initialization_ (whose semantics are derived from assignment.)

In Java, the if statement is used a lot (too much IMO but i don't think we should fight to change that) so it may make sense to be able to reuse an existing local variables.

Yes, this has come up before.  I agree that there are cases where we might want this (there's one distinguished case where we almost cannot avoid this), but in general, I am pretty reluctant to go there -- I think this is incremental complexity (and encouragement of more mutability) with not enough commensurate benefit.




    ## Possible extensions

    There are a number of ways we can extend `let` statements to make
    it more
    useful; these could be added at the same time, or at a later time.

    #### What about partial patterns?

    There are times when it may be more convenient to use a `let` even
    when we know
    the pattern is partial.  In most cases, we'll still want to
    complete abruptly if the
    pattern doesn't match, but we may want to control what happens. 
    For example:

    ```
    let Optional.of(var contents) = optName
    else throw new IllegalArgumentException("name is empty");
    ```

    Having an `else` clause allows us to use a partial pattern, which
    receives
    control if the pattern does not match.  The `else` clause could
    choose to throw,
    but could also choose to `break` or `return` to an enclosing
    context, or even
recover by assigning the bindings.

I don't like that because in that case "let pattern else ..." is equivalent of "if instanceof pattern else ... " with the former being expression oriented and the later statement oriented. As i said earlier, i don't think we should fight the fact that Java is statement oriented by adding expression oriented variations of existing constructs.

We haven't talked about let expressions yet; this is still a statement.

It's a fair point to say that the above example could be rewritten as an if-else, and when the else throws unconditionally, we still get the same scoping.  Or that it can be rewritten as

    if (!(pattern match))
        throw blah

On the other hand, people don't particularly like having to invert the match like this just to get the scoping they want.

In any case, the real value of the else block is where you want to continue (and merge the control flow) with default values of the bindings set in the else clause (next section).  Dropping "else" makes this extremely messy.  And once you have else, the rest comes for the ride.



    #### What about recovery?

    If we're supporting partial patterns, we might want to allow the
    `else` clause
    to provide defaults for the bindings, rather than throw.  We can
    make the bindings of the
    pattern in the `let` statement be in scope, but definitely
    unassigned, in the
    `else` clause, which means the `else` clause could initialize them
    and continue:

    ```
    let Optional.of(var contents) = optName
    else contents = "Unnamed";
    ```

    This allows us to continue, while preserving the invariant that
    when the `let`
statement completes normally, all bindings are DA.

It fails if the "then" part or the "else" part need more than one instruction.
Again, it's statement vs expression.

No, it's still a statement.  I don't know where you're getting this "statement vs expression" thing from?



    #### What about guards

    If we're supporting partial patterns, we also need to consider the
    case where
    the pattern matches but we still want to reject the content.  This
    could of
    course be handled by testing and throwing after the `let`
    completes, but if we
    want to recover via the `else` clause, we might want to handle
    this directly.
    We've already introduced a means to do this for switch cases -- a
    `when` clause
    -- and this works equally well in `let`:

    ```
    let Point(var x, var y) = aPoint
    when x >= 0 && y >= 0
    else { x = y = 0; }
    ```


It can be re-written using an if instanceof, so i do not think we need a special syntax

  int x, y;
  if (!(aPoint instanceof Point(_ASSIGN_ x, _ASSIGN_ y) && x >= 0 && y >= 0)) {
   x = 0;
   y = 0;
  }

All let statements can be rewritten as instanceof.  Are you arguing that the whole idea is silly?


"Let ... in" is useful but i don't think it's related to the current proposal, for me it's orthogonal. We can introduce "let ... in" independently to the pattern assignment idea, and if the pattern assignment is already in the language, then "let ... in" will support it.

Yes and no.  You are correct that we could do either or both independently.  But it's not my job just to design each feature in a locally optimal way; it's my job to ensure that the features we design will fit together when they meet up in the future.   The fact that the construct generalizes in this way is an important part of the design even if we don't plan to do this part now.

Reply via email to