-
Notifications
You must be signed in to change notification settings - Fork 38
Spread anywhere feature #692
Spread anywhere feature #692
Conversation
Would you add printing tests? |
What is |
Add a file in tests/print or extend an existing one where list examples are. It will tell you how things print, and whether printing is idempotent, so you don't get different results if you format twice. |
Thanks, I think I understand. I'll give it a try. |
See how the syntax of normal lists is preserved by printing. |
tiny concern, but would it be better not allowing this expression at all ? lists are not okay when manipulation is occurred at non-head position. Once spreadings are used inadvertently, it would cause performance problem. By now, list spreading guarantees constant time |
c7969a8
to
3459747
Compare
IMHO, it's still a useful feature. For some reason. Belt.List.concatMany([list{1, 2, ...x}, list{3, ...x}, list{4, ...x}, list{5}])
// or
Belt.List.concat(list{1, 2, ...x}, list{3, ...x})
// or
List.concat(list{list{1, 2, ...x}, list{3, ...x}}) Second, I think if we support @ operator (like OCaml), the verbose issues will be moderated. But for the existence of list open token // pretend we have operator @
list{1, 2, ...x} @ list{3, ...x} @ list{4, ...x} @ list{5}
list{1,2, ...x} @ list{3, ...x} If we let spread show anywhere, we can just write: list{1, 2, ...x, 3, ...x, 4, ...x, 5}
list{1, 2, ...x, 3, ...x} I think that's more concise, right? And, as far as I know, literally, the word "spread" itself is not intuitively associated with constant time operation, unlike "prepend". Finally, the performance issue you mentioned does exist while this feature is being misused. But this feature will not downside any performance of existing code, and I think (I'm not sure) concatenate seems can be optimized in some way. So I think it's still a good deal. I'll always wait for more suggestions. |
Before adding this to the language, we should take a closer look at the design of this feature.
When making design decisions regarding new syntax in the language, it’s also important to weigh the costs, not all of which are performance, against the potential benefits. The following things can happen:
I feel like this more design work needed before going into implementation mode. |
Let me explain a bit why this feature it is useful and why you should not worry about performance. This feature is very helpful for expressing lots of algorithms, for example Add(e1,e2) => list {... compile(e1), ... compile(e2), Add } It is much more readable than the alternatives, and as efficient as you could, in theory the compiler can do So the argumets are:
Before we add this feature, this used to be a bug, the syntax was accepted but not reported error, it is worse so With regard to developer resources, this is the feature I would like to add on day one when making BuckleScript, Hope my explanantions make the motivation clear. Edit: note this implementation should be improved, @butterunderflow no regressions should happen, |
@@ -114,7 +100,7 @@ let arr = [|x;y|] | |||
let [|arr;_|] = [|1;2;3|] | |||
let record = { x with y } | |||
let { x; y } = myRecord | |||
let myList = x :: y | |||
let myList = Belt.List.concatMany [|x;y|] |
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 case should be specialized?
- this case too
{ ... x}
@@ -2,6 +2,7 @@ let x = list{} | |||
let x = list{1} | |||
let x = list{1, 2} | |||
let x = list{1, 2, 3} | |||
let x = Belt.List.concatMany([list{1, 2, ...x}, list{3, ...x}]) | |||
|
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.
could this be improved? print it as list{ 1, 2, ...x , 3 , ...x}
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.
It could be, but just by changing the printer can cause some problems. For example, list{. . x, . .y} and Belt.List.concatMany([x, y]) will be printed as the same thing. I am still trying to solve this problem.
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.
can you add an attribute to Belt.List.concatMany to avoid accidental simplifications?
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 is what is done for string templates, I believe, to differentiate from normal string concatenation.
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.
Check what isTemplateLiteral
does.
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.
Thank you for all your suggestions, I'll learn more about that.
Made some changes to ensure that the printer output and source are the same. I would have to ask you to review it again, thanks! |
Thanks for the context @bobzhang 👍 |
src/res_core.ml
Outdated
(* | (true (\* spread expression *\), expr, _) :: exprs -> | ||
* let exprs = check_all_non_spread_exp exprs in | ||
* makeListExpression loc exprs (Some expr) | ||
* | exprs -> |
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.
instead of comment unused code, can you just remove it
src/res_parsetree_viewer.ml
Outdated
(Longident.Ldot (Longident.Lident "Belt", "List"), "concatMany"); | ||
} | ||
when hasSpreadAttr expr.pexp_attributes -> | ||
true |
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.
simplified: -> hasSpreadAttr exp.pexp_attributes
6 │ | ||
7 │ let list{...x, ...y} = myList | ||
8 │ | ||
9 │ type t = {...a} | ||
|
||
List pattern matches only supports one `...` spread, at the end. | ||
Explanation: a list spread at the tail is efficient, but a spread in the middle would create new lists; out of performance concern, our pattern matching currently guarantees to never create new intermediate data. |
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.
we may need update the docs about pattern in later commits, it is not supported since it is not deterministic
@@ -2,6 +2,8 @@ let x = list{} | |||
let x = list{1} | |||
let x = list{1, 2} | |||
let x = list{1, 2, 3} | |||
let x = list{1, 2, ...x, 3, ...x} | |||
let x = Belt.List.concatMany([list{1, 2, ...x}, [list{3, ...x}]]) | |||
|
|||
let x = list{ |
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.
can you add some more test cases, some edge cases like:
let x = list{ ...xs}
let x = list{1, ...xs}
let x = list{xs, ... ys}
let x = list{ ...xs, ... ys}
@butterunderflow looks good to me once the comments are addressed. |
Done. Please check again, thanks! |
@butterunderflow Thanks, cannot wait for to use it in the course! |
@butterunderflow would you add a line to CHANGELOG.md |
Done. Please check #698 |
Feature request from #670.
The new feature will allow spread anywhere in a list creation expression.
For example, list creation like
will no longer trigger an error anymore, but parsed to
Can anyone help review this feature PR? Thanks ^v^