April 10 2014 Meeting Notes
Allen Wirfs-Brock
allen at wirfs-brock.com
Fri Apr 25 09:10:06 PDT 2014
On Apr 25, 2014, at 4:53 AM, Kevin Smith wrote:
> It seems to me that generators are not the best mechanism to express resource management ("abstract over expensive resources") because the programmer of the generator can never guarantee that the consumer will exhaust it. If we want direct language support for resource management, then a proposal should be crafted to add that as a distinct feature.
>
We routinely make use case based argument to justify new features. But once we have a feature, we can't expect it to be used only for the original use cases that motivated its inclusion. In integrating a feature we need to look at a feature's actual semantics and how those semantics interact with the semantic of existing and proposed features. At that point, we shouldn't be thinking about whether a particular use case is "good" or "bad" . It is only the semantic interactions that we should consider.
In this case we have try-finally statements as an existing feature. The semantics of this feature is a bounded execution scope with a cleanup action on completion. This feature is widely used and has always been internally consistent and reliable, expect for catastrophic external failure or intervention (ie, externally imposed process termination, power failure, etc). People use it for all sorts of things, including bounded resource management.
We then added a new feature, generators, which in some cases changes the semantics of try-catch. No longer is the execution of the try block bounded in a manner that guarantees that the finally block will execute after completion of the try block. That seems like a significant semantic change to try-finally and a usage hazard that we should be concerned about.
Support for @@return and its use by for-of would help to restore the try-finally invariants for what is likely to be the most commonly seen semantic feature composition (I'm not taking about use cases here) of for-of, generators, and try-finally. That's an imperfect solution because when for-of isn't used it places a burden on the JS programmer to do manual work to ensure the try-finally invariant of a (possibly) generator invocation. However, it seems like a significant improvement over the currently spec. behavior which just flat-out breaks a generator's try-finally invariant for any abrupt termination of a for-of loop.
The @@return solution still seems like a good compromise design. However, there is another way to attack this problem.
The fundamental problem is that any generator that looks anything like this:
function *f() {
try {yield} finally {postcondition()}
}
has an unreliable try-finally block. Whatever the programmer things is going to happen, may not actually happen. The problem is the yield (a new feature that is corrupting the legacy semantics of try-finally).
People will write code like this if we allow it. But we don't have to allow. We can preserve the semantics of try-finally by simply making the occurrence of the 'yield' operator syntactically illegal within the try block of a try-finally.
We could do this. The parameterized grammar notation we now use in the ES6 spec. makes it fairly easy to specify that you can't write code like the above.
Should we do it? I'm not sure. I still think that @@return is a reasonable but imperfect alternative that allows generator authors to continue to use what many think is a useful feature. Outlawing 'yield' in a try-finally is a almost perfect solution to the semantic impedance mismatch between try-finally and generators. But we also loose some expressiveness.
Allen
More information about the es-discuss
mailing list