-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Alternative strawman #20
Comments
That's pretty awesome, thanks for kicking this off! Give me a couple of
days to digest this and factor this in (I'll be ooo next week for
Thanksgiving so will get back after it), but wanted to acknowledge that I
got the message and that I'll be looking into the trade offs and
alternatives!! Thanks!
Sam
(sent from phone, apologies for the brevity)
…On Nov 18, 2017 11:10 PM, "Isiah Meadows" ***@***.***> wrote:
I decided to take a bit to sketch out an alternative strawman
<https://gist.github.com/isiahmeadows/b9feb99051fdc271e84aeb0d691889da>,
to see what I could do. Key takeaways:
- Coming up with a concise, well-defined syntax and semantics set is
hard. As if that wasn't already obvious, though... 😄
- I had to create an *additional* implicit context channel to avoid
this conflicting issues. It was *much* better than introducing this
footgun: forEach(array) do (item) { this.consume(item) }.
- I had to figure out a better system to solve the scoping issue, and
I decided to settle on no sigil on top-level DSLs, @ for dependent
DSLs, and tentatively :: for top-level control flow DSLs and : for
dependent control flow DSLs. I know the former *could* conflict with
decorators and the latter with labels, but I made mention of how to address
it (as in, decorators and labels come first, respectively).
- Managing control flow is *incredibly hard*, even at the conceptual
level. It's bad enough to just incorporate synchronous, immediate values
into the mix, but add the ability to suspend the context, and I quickly had
to jump to coroutines, just to have a sane execution model for the DSLs
themselves.
- Managing completions without reifying them is pretty difficult to
come up with solutions for. It wasn't exactly a simple thought process to
go from reified completions to just using syntax. I used try/catch as
a base because they already deal with abrupt completions.
- I tried dealing with the exact completions in the spec when modeling
the control flow DSLs, but I found a few complications and glitches with
that reasoning (and why I opted to model my "inline completions" based on
outside behavior instead):
- break could mean the DSL itself, or it could mean an outer loop.
- continue is really just a glorified block-level return, so
there's little point in discerning them.
- return breaks out of the loop and triggers the same exit sequence
as break does.
- throw can work a lot like return, but it can also just be an
error handleable by the DSL itself.
- Sometimes, you want to short-circuit and return a value for the
DSL's callee, like in the select example here in this repo's
README. This can't be modeled with a completion in terms of the current
spec.
Here's a few other features specific to my rendition:
- The implicit scope is accessible, and I do make it possible to read
from and write to members of the context, to make it much more transparent
and user-friendly.
- I also took into account the possibility of computed properties, and
tried to support that use case.
- I found it easier to treat control flow arguments as thunks, and
similarly, I made the syntactic variant use call-by-name, rather than
call-by-value.
/cc @samuelgoto <https://github.com/samuelgoto> @rwaldron
<https://github.com/rwaldron>
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#20>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAqV6g9ZgE8uSpsgl9gQJZ_3krZ_IgCmks5s39RfgaJpZM4QjSG7>
.
|
Wow, lots of good stuff in this alternative exploration. Let me try to unpack and discuss piece by piece (not sure what's the best way to do this, but lets give it a try). Here are some of the ideas that I really liked but needs further clarification. @@this, : and ::This seems like a very interesting idea, but I'm not sure we are thinking of the same thing. Let me try to get some clarity here.
Is @@this something that is supposed to be used by the user? That is, does the user ever make a reference to @@this or sets value in @@this? If so, could you give me a concrete example on how @@this is used?
I'm not sure how you are defining "top-level DSLs" and "dependent DSLs", but it sounds a little awkward that you have to make the distinction between the two at a syntax level (i.e. use I'm not sure what to call these, but I've seem a pattern that I agree that needs to be named / better understood.
On one hand, I think that, perhaps, the key distinction here is how to resolve the identifiers. In the select (foo) {
when (bar) { // there needs to be somehow a connection between when and select
foreach ([1, 2, 3]) do (item) { // foreach, on the other hand, is de-coupled from everything else
console.log(item)
}
}
} Is this the problem that you are trying to solve with with ::select (foo) {
:when (bar) { // : desugars to this.when(bar, function() { ... })
::foreach ([1, 2, 3]) do (item) { // :: desugars to foreach([1, 2, 3], function() { ... })
console.log(item)
}
}
} If so, why does one need to make a distinction between select (foo) { // by default, desugars to select(foo, function() { ... })
:when (bar) { // : desugars to this.when(bar, function() { ... })
foreach ([1, 2, 3]) do (item) { // by default, desugars to foreach([1, 2, 3], function() { ... })
console.log(item)
}
}
} Pushing this even further, if we reverted the semantics between select (foo) { // by default, desugars to select(foo, function() { ... })
::when (bar) { // :: desugars to this.when(bar, function() { ... })
foreach ([1, 2, 3]) do (item) { // by default, desugars to foreach([1, 2, 3], function() { ... })
console.log(item)
}
}
} Does that make sense? Just so that I understand, the introduction of select (foo, function() {
(this.when ? this.when : when) (bar, function() {
(this.foreach ? this.foreach : foreach) ([1, 2, 3], function (item) {
console.log(item)
})
})
}) Separately, what's the role of |
(These are answered somewhat out of order, but I've roughly sorted them topically.)
|
Lots of good observations again, let me try to break things down and comment things separately.
I think that's a fairly reasonable route to take too. I do actually think that dealing with non-local abrupt termination (e.g. break and continue and return) could be looked at separately (i.e. purely as a sequencing strategy). Let me dive into that route for a second. What if we used the block param's parameters list to pass For example: foo {
::bar {
}
} As this: // all block params takes as an argument an object that can
// contain a @@this context passed in via a Symbol.parent
// key.
foo (({[Symbol.parent: @@this]}) => {
// ::method turns into @@this.method()
@@this.bar (({[Symbol.parent]}) => {
})
}) So that, for example, function foo(block) {
block({[Symbol.parent]: {
bar(inner) {
inner()
}
}});
} So, back to our canonical example: select(foo) {
::when(bar) {
}
} Gets transpiled to: select(foo, ({[Symbol.parent]: @@this1}) => {
@@this.when(bar, ({[Symbol.parent]: @@this2}) => {
// ...
// break and continue throw SyntaxError here
})
}) And maybe nesting could be done through function select(expr, block) {
// block is an arrow function, so block.call() sets @@this
// which can be accessed through ::
block({[Symbol.parent]: {
when(cond, inner) {
if (expr == cond) {
inner.call(); // guaranteed not to have a break/continue statement
}
}
}
});
} WDYT? |
Not super keen on it. The reason being,
To clarify, that's why I factored out the control flow idea out into a separate file from the main proposal. Thought I'd correct you with the syntax of my proposal: there's an extra // Correct
foo(...args) do {
// ...
}
// Incorrect
foo(...args) {
// ...
} The reason for the extra keyword is to avoid future hostility, to avoid ambiguity with parameterized blocks, and to avoid forcing a particular brace style. // Conflicts with the current pattern matching proposal
match(foo) {}
// Currently a function call + block
foo(...args)
{
// ...
}
// This would *not* be a problem
foo(...args) do
{
// ...
}
// Is this a parameterized block or a double call expression?
foo(bar) (baz) {
// ...
}
// This would *not* be a problem
foo(bar) do (baz) {
// ...
} |
I'm getting increasingly excited about the approach that I outlined because it addresses a consistent feedback that I've been getting that messing with I tried to write down a simpler version of my explanation here and started prototyping it with the transpiler here. I'm going to update the text of the proposal to reflect this formulation, but I think it is a step forward in the right direction (albeit it doesn't address yet break/continue/yield/await, but like I said earlier, I think we should look at nesting/scoping separately from abrupt interruption). |
done. https://github.com/samuelgoto/proposal-block-params |
@samuelgoto Don't forget to add the |
I decided to take a bit to sketch out an alternative strawman, to see what I could do. Key takeaways:
this
conflicting issues. It was much better than introducing this footgun:forEach(array) do (item) { this.consume(item) }
.@
for dependent DSLs, and tentatively::
for top-level control flow DSLs and:
for dependent control flow DSLs. I know the former could conflict with decorators and the latter with labels, but I made mention of how to address it (as in, decorators and labels come first, respectively).try
/catch
as a base because they already deal with abrupt completions.break
could mean the DSL itself, or it could mean an outer loop.continue
is really just a glorified block-levelreturn
, so there's little point in discerning them.return
breaks out of the loop and triggers the same exit sequence asbreak
does.throw
can work a lot likereturn
, but it can also just be an error handleable by the DSL itself.select
example here in this repo's README. This can't be modeled with a completion in terms of the current spec.Here's a few other features specific to my rendition:
/cc @samuelgoto @rwaldron
The text was updated successfully, but these errors were encountered: