-
Notifications
You must be signed in to change notification settings - Fork 25
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
Update explainer to introduce ~()
for partial application
#49
Conversation
I see no mention of what happens when you use the same ordinal placeholder multiple times const surround = String~(?1, ?0, ?1);
surround("text", "__"); // "__text__" ? The explainer doesn't say if it is forbidden or if the argument is applied twice as expected |
You overlooked it - check line 115. |
Although, the |
README.md
Outdated
printArgs(); // prints: a, b, c | ||
printArgs(1, 2, 3); // prints: 1, 2, 3 | ||
|
||
const swapAC = printArgs~(?2, ?, ?0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This really confuses me. Just reading this, my first thought is that the unbound ?
should be equivalent to a ?3
because it's directly right of a ?2
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would make the introduction of an ordinal placeholder into a refactoring hazard:
// original code
const g = f(?, 1, ?);
// g is (roughly): (_0, _1) => f(_0, 1, _1);
// Now I need to add a 3rd parameter to `g`, but pass it as the first parameter to `f`:
const g = f(?2, ?, 1, ?);
// ^^ (inserted/changed)
// g is now (roughly): (_2, _0, _1) => f(_2, _0, 1, _1);
// ^^ ^^
If the numbering were to continue from 2, I would have to rewrite the entire expression:
const g = f(?2, ?0, 1, ?1);
// ^^ ^ ^
// g is now (roughly): (_2, _0, _1) => f(_2, _0, 1, _1);
// ^^ ^^
Otherwise I would end up with something completely unexpected:
// original code
const g = f(?, 1, ?);
// g is (roughly): (_0, _1) => f(_0, 1, _1);
// Now I need to add a 3rd parameter to `g`, but pass it as the first parameter to `f`:
const g = f(?2, ?, 1, ?);
// ^^
// g is now (roughly): (_0, _1, _2, _3, _4) => f(_2, _3, 1, _4);
// ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^
// ~~ ~~ (ignored)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For your first comment example, do you mean:
-// g is now (roughly): (_2, _0, _1) => f(_2, _0, 1, _1);
+// g is now (roughly): (_0, _1, _2) => f(_2, _0, 1, _1);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, what makes the ?
equivalent to _0
or _1
? Do they use a completely separate counter? Could I have f~(?1, ?, ?)
, which would be similar to (_0, _1) => f(_1, _0, _1)
?
I think it might be clearer to forbid mixing ordinal and non ordinal placeholder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a fair point, and my current explanation is also a refactoring hazard. In the explainer currently, any ordinal placeholder reserves a position that a normal placeholder would otherwise occupy:
f~(?, ?, ?) // implicitly f~(?0, ?1, ?2)
f~(?0, ?, ?) // implicitly f~(?0, ?1, ?2)
f~(?, ?0, ?) // implicitly f~(?1, ?0, ?2)
Its possibly better for normal placeholders to always just increment from 0, as this works better with refactoring:
// above examples
f~(?, ?, ?) // implicitly f~(?0, ?1, ?2)
f~(?0, ?, ?) // implicitly f~(?0, ?0, ?1)
f~(?, ?0, ?) // implicitly f~(?0, ?0, ?1)
// refactoring f~(?, ?, ?) by inserting an ordinal argument anywhere
// `^` - inserted
// `=` - same
f~(?0, ?, ?, ?) // f~(?0, ?0, ?1, ?2)
// ^^ ======= ^^ ==========
f~(?, ?1, ?, ?) // f~(?0, ?1, ?1, ?2)
// = ^^ ==== == ^^ ======
f~(?, ?, ?5, ?) // f~(?0, ?1, ?5, ?2)
// ==== ^^ = ====== ^^ ==
We could ban mixing them, but as long as we choose a consistent numbering mechanism there's no reason to ban mixing them outright in the language. A linter could ban mixing them instead, leaving it open to override a lint rule in special circumstances.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated the explainer to indicate that the implicit order of non-ordinal placeholder arguments is unaffected by ordinal placeholder arguments, and added an example for refactoring to explain why this is intended to avoid a refactoring hazard.
I think its too early to ban the combination outright, as minimizing the impact of any potential refactoring in user code seems like a valid reason to permit the combination.
Merging, thanks for the feedback! |
|> add(7, ?) | ||
|> clamp(0, 100, ?); // shallow stack, the pipe to `clamp` is the same frame as the pipe to `add`. | ||
// accept a fixed argument list: | ||
const numbers = ["1", "2", "3"].map(parseInt~(?, 10)); // [1, 2, 3] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I love this example. "One way to fix a problem you probably didn't know was plaguing you."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made sure to add this example to my slides 😁
This make the following changes to the proposal:
~
prefix to denote a partially applied argument list (i.e.,f~(?, x)
).?0
ordinal placeholders....
"rest of the arguments" placeholder.new
.Fixes #48
Fixes #43
Fixes #5