Here's my review of "SE-0073 
<https://github.com/apple/swift-evolution/blob/master/proposals/0073-noescape-once.md>:
 Marking closures as executing exactly once".

> What is your evaluation of the proposal?

+1. I think this is a good idea and should be accepted (without extending the 
proposed scope).

However, I think the proposal should be more explicit about the case when (and 
whether) the block itself throws. Specifically, I think we should highlight 
that the criterion that

> it must not be executed on any path that throws


implies that a @noescape(once) parameter itself cannot throw (until another 
language change allows otherwise). Consider this use case:

    final class Database {
      final class Transaction { ... }
      // Not allowed by SE-0073:
      func transact(_ apply: @noescape(once) (Transaction) throws -> ()) 
rethrows
    }

    func incrementScore(db: Database, game: String) throws -> Int {
      let oldScore: Int
      // This use of "@noescape(once) ... throws" *could* be ok if the error was
      // unconditionally propagated out of the scope of uninitialised variables:
      try db.transact { tx in
        oldScore = try tx.read(key: "\(game).score")
        try tx.update(key: "\(game).score", value: oldScore + 1)
        try tx.update(key: "\(game).updatedAt", value: NSDate())
      }
      return oldScore
    }

Being able to throw out of a @noescape(once) block would be useful in cases 
like this, as it would naturally allow rolling back a transaction. But it would 
complicate the language by requiring that no one catches the error in the scope 
where uninitialised variables are defined. I suggest adding this remark to the 
Future directions.

> Is the problem being addressed significant enough to warrant a change to 
> Swift?

Yes. I'm looking forward to being able to initialise immutable variables in 
dispatch_sync blocks and such without needing to resort to defining them as 
`var`.

> Does this proposal fit well with the feel and direction of Swift?

Yes it does, it aligns nicely with the trailing closure syntax that allows for 
the emulation of control flow constructs with library code. And as we know, the 
control flow constructs already allow the delayed initialisation of local 
variables.

> If you have used other languages or libraries with a similar feature, how do 
> you feel that this proposal compares to those?

With a similar feature, I have only used languages (in the sense of "used in 
anger") where the delayed initialisation is allowed by allowing an undefined 
state (e.g. C++). For a not-really-applicable-to-Swift alternative approach, 
Haskell's laziness allows the recursive definition of variables for a similar 
effect.

Finally, I think it's interesting that the requirement for @noescape(once) 
arguments to be unconditionally executed has a similarity to linear type 
systems (Wikipedia <https://en.wikipedia.org/wiki/Substructural_type_system>) 
and uniqueness or references. Except in this case, the reference is not to an 
object but a function. Such a function reference bears a certain similarity to 
the deinit of a uniquely held object. I think the proposed feature may later 
merge with a bigger language update that brings reference uniqueness to the 
type system.

> How much effort did you put into your review? A glance, a quick reading, or 
> an in-depth study?


Between quick reading and in-depth study.

— Pyry

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to