domenic / proposal-blocks

Former home of a proposal for a new syntactic construct for serializable blocks of JavaScript code
215 stars 5 forks source link

Why not a keyword before function? #5

Closed jakearchibald closed 6 years ago

jakearchibald commented 6 years ago

Similar to #2 I guess.

The proposal introduces a lot of new syntax to describe something that becomes callable with arguments, so why not:

deferred function whatever(arg1, arg2, …etc) {
  // …
}

As with the current proposal, whatever.reify() returns the actual callable.

This means existing function syntax can be used, such as async and *.

j-f1 commented 6 years ago

As with the current proposal, whatever.reify() returns the actual callable.

Since this is declared as a function, why not make whatever() return the actual callable?

surma commented 6 years ago

Yeah, I think the arguments would be the same as in #2.

jakearchibald commented 6 years ago

I guess the specific argument is https://github.com/domenic/proposal-blocks/issues/2#issuecomment-389032041.

I get stuck on worker<someVar>{| … |} desugaring to worker({| … |}, { someVar }). It seems really syntactically complex compared to:

await worker(deferred function (endpoint) {
  …
}, { someVar });

(where the worker helper will send someVar and the deferred function to a worker, and call the function with someVar)

felixfbecker commented 6 years ago

I myself trip over worker{| |} getting desugared to worker({| |}) too, without the parenthesis it reminds me more of a go struct declaration than a function call. And with worker<someVar> it gets really confusing because that syntax is used by TypeScript for generic type parameters (and by every other language with generics).

I like the proposal in this issue. I think it doesn't even have to be called a deferred function, as you still pass it into a worker() function (which is great, because it lets us write different backends).

From my perspective, the only problem this whole proposal needs to solve is this one:

The JavaScript engine, and tooling ecosystem, has no way of knowing that these functions are not real closures; for example, they allow using closed-over variables.

It would be nice if the solution was as simple as a keyword like isolated that prevents any reference to a variable from outside the function scope, forcing you to declare the inputs as parameters, which the worker function can pass in as cloned values. Actually, someone could probably write an eslint/tslint rule right now that works with a comment like /* @isolated */ to enforce this. It could even be used without WebWorkers, e.g. just to enforce pure map()/filter() callbacks.

domenic commented 6 years ago

Let's roll this into #2, which has seen more discussion.