Hi,

We had some discussion recently about reforming the for-loop syntax since we'll be switching it to external iterators and it's a bit deceptive to the user to be writing a lambda-pattern there. Many people have suggested we use a simple and familiar:

  for <pattern> in <expr> { ... }

form. I am inclined to agree with this though I should point out a few minor concerns:

  - It's a new keyword. We've been really, really trying not to do that.

  - No-pattern form now requires a dummy pattern. That is, we can't do:

      for 10.times { ... }

    anymore, rather we have to write:

      for _ in 10.times() { ... }

    which is possibly unsightly. We can't disambiguate patterns from
    exprs just by peeking at them. I don't know. The 10.times thing
    always seemed a little clever to me anyways.

  - The 'do' form starts to look a little lonely / incongruous. We use
    it presently for passing-in-a-closure when a function takes an
    optional value, such as:

      do hashmap.find_or_insert_with(k) {
          def()
      }

    Given we're discussing macro-izing the other main use of 'do' to
    generate an owning thunk Trait object, It's not entirely clear to
    me that this pattern alone warrants keeping 'do'.

Anyway, neither of these seem like showstoppers to me, I just thought I'd mention them in passing in case anyone wanted to chew on possible solutions (or point out other issues with for .. in that I didn't picture yet).

I found it more interesting to note that, should we take 'in' as a new keyword, it's a perfectly reasonable keyword to reuse for the putative "allocation expressions" we've been talking about needing for supporting C++-like placement-new. That is, evaluating an expression "into" a bit of memory provided by one of the operands. This is useful for arenas, GCs, custom smart pointers and memory pools, etc. We've been somewhat concerned that we're sealing up the language without the ability to implement evaluate-into-place forms; evaluating into a local and then moving into a place doesn't actually work either, due to unknown-sized types (vectors and such). I think it kinda has to be a built-in expression.

So I'm wondering how this looks for people:

   <expr> in <expr>

as a new bottom-precedence binop. The RHS is evaluated first, to a *mut u8 or perhaps some lang-item trait we define for "the interface to a memory allocator", then the LHS is "evaluated into it". I do not _think_ it would collide with "for <pat> in <expr>", unless my eyes confuse me. It might need to be an unsafe expr; not clear.

Any thoughts? Ghastly? Convenient? I don't much like evaluating RHS before LHS but in this case it seems like it'd be necessary. And lest you complain that reusing 'in' this way is a comprehension menace, I'd point out that we reuse several other keywords in differing contexts ('for', 'mod', 'self', 'super') without too much confusion.

-Graydon
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to