| 00:48 | <Justin Ridgewell> | If it's limited to scoped using and not general mutability, I think you can polyfill on top of AsyncContext and only instrument await and yield statements. |
| 00:49 | <Justin Ridgewell> | I know we talked about this before and I said otherwise, but I can't remember why I said it wasn't possible before. |
| 04:18 | <Steve Hicks> | But I think that's the problem - it can't be limited to scoped
That function gives no syntactic indication that it needs any extra transpilation... in fact, thinking about it further, it violates the principle that functions you call shouldn't be able to change your context. |
| 04:23 | <Justin Ridgewell> | That example wouldn't be possible, but using using span = enterSpan(…) could be |
| 04:24 | <Steve Hicks> | how would you define enterSpan in that case? |
| 04:35 | <Justin Ridgewell> | The same? |
| 04:35 | <Justin Ridgewell> | The difference is you expected enterSpan to cause the mutation, and I'm expecting the using span … to do it |
| 17:06 | <Steve Hicks> | This is the disposable[Symbol.enter]() idea, but AIUI, it's a non-starter if it only works syntactically - i.e. you still need to be able to call it reflectively for composability. |
| 17:07 | <Steve Hicks> | Case in point: Span.prototype[Symbol.enter] would need to call AsyncContext.Mutation.prototype[Symbol.enter] transitively. |
| 17:07 | <Steve Hicks> | and it couldn't use using syntax for that. |
| 17:27 | <nicolo-ribaudo> | For
|
| 17:33 | <nicolo-ribaudo> | And you can still leak a little bit, but:
|
| 17:33 | <nicolo-ribaudo> | And the error could point to the stack trace of where you did enter without then disposing it |
| 17:34 | <Steve Hicks> | I think you need to store two locals - one for oldContext and one for updatedContext and then line 15 wants to compare current !== updatedContext |
| 17:34 | <nicolo-ribaudo> | True, right (updated) |
| 17:37 | <Steve Hicks> | And then the idea is that
would work because the suspension would restore the entry context? But if |
| 17:38 | <nicolo-ribaudo> | Yes and yes |
| 17:38 | <Steve Hicks> | And any non-syntactic access to the protocol should still at least be sound |
| 17:39 | <nicolo-ribaudo> | And the whole program should also have a check at the end that checks you didn't forget to close anything |
| 17:39 | <Steve Hicks> | I don't think you strictly need Symbol.enter for these checks. |
| 17:39 | <nicolo-ribaudo> | So that even a program that just does x1[Symbol.enter]() throws when it ends |
| 17:39 | <Steve Hicks> | though it would certainly be nicer to have |
| 17:39 | <nicolo-ribaudo> | I don't think you strictly need |
| 17:43 | <Steve Hicks> | So does run also verify that the "outgoing" context hasn't changed? |
| 17:44 | <Steve Hicks> | And is there any precedent for this sort of behavior where we allow the unsound thing to happen, but only throw an error later after it becomes more obvious? |
| 17:45 | <nicolo-ribaudo> | So does |
| 17:49 | <Steve Hicks> | This would work fine with generators if yield had the same behavior as await; otherwise, it would effectively make a yield within an enterWith block be an error. |
| 17:50 | <Steve Hicks> | unless the generator was fully iterated in a single outer context |
| 17:52 | <Steve Hicks> | one could imagine a weird solution where the yield would somehow capture the mutations and replay them on top of the new re-entered context, but that doesn't seem reasonable |
| 17:55 | <nicolo-ribaudo> | Agree — I think we need to make yield capture/restore if we don't want to prevent enterWith from happening in the future |
| 17:55 | <Steve Hicks> | This makes it impossible to implement dispatch-context iterator helpers (in userland) as generators |
| 17:56 | <nicolo-ribaudo> | In a world with enterWith, could we do something like this with a metaproperty? ``` let x = yield foo; using _ = yield.nextCallerContext ``` |
| 17:57 | <nicolo-ribaudo> | Where yield.nextCallerContext gives you the context of the .next call |
| 17:57 | <nicolo-ribaudo> | And you can "enter a snapshot" |
| 17:58 | <Steve Hicks> | that seems feasible |
| 18:12 | <Steve Hicks> | So I guess that leaves ^ as my main concern - do we think this sort of thing could actually land? |
| 18:13 | <nicolo-ribaudo> | I don't know, nothing comes immediately to my mind |
| 18:13 | <nicolo-ribaudo> | I'll look around |
| 18:13 | <Steve Hicks> | (and aside, I'm a little sad that I won't be able to rip out the over-complicated transpilation for generators) |
| 18:18 | <nicolo-ribaudo> | Instead of transpiling the generator, could you wrap it in a function that calls .next setting the original generator context first? |
| 19:49 | <Steve Hicks> | That's an interesting idea, I'll need to look into that. |
| 19:51 | <Steve Hicks> | it's a little awkward for class methods, but I think we do something similar when downleveling async methods |
| 22:19 | <Steve Hicks> | I prototyped a quick proof-of-concept that it's possible to leverage most of an existing implementation and add a disposable enterWith by just replacing AsyncContext.Variable with a new implementation that indirects through a single "real" variable: https://gist.github.com/shicks/0cd7e9b06535793c137934cc52ed12ce |
| 22:20 | <Steve Hicks> | I don't think an analogous approach would work for Scratch that - you need to transpile the keyword anyway, and if you do so, you only need to wrap that particular generator. |