19:29 | <jschoi> | I don't know. F# computation expressions don't feel as fluid to me as FLWOR/FLWOS syntax, and the ability to introduce arbitrary "keywords" inside such a block isn't great for static analysis. That said, being able to add a distinct or count in a F# query expression is an improvement over C#'s LINQ syntax With regards to static analysis, I don’t think there would be a fundamental problem with static analysis of context blocks beyond having to analyze decorated constructs in general. As long as the analyzer knows the identity of a decorator, then it knows the types of the callbacks that are involved in its decorated constructs.
But it’s true that F# computation expressions are slightly more verbose than bespoke LINQ FLOWR/FLOWS syntax. That’s the price of its being generic. |
19:35 | <rbuckton> | With regards to static analysis, I don’t think there would be a fundamental problem with static analysis of context blocks beyond having to analyze decorated constructs in general. As long as the analyzer knows the identity of a decorator, then it knows the types of the callbacks that are involved in its decorated constructs.
But it’s true that F# computation expressions are slightly more verbose than bespoke LINQ FLOWR/FLOWS syntax. That’s the price of its being generic. It depends to what level you want to support F#-style computations. F# allows custom keywords using a [<CustomOperation("name")>] attribute and you can specify options in that attribute that affect parsing, such as AllowIntoPattern , IsLikeJoin , MaintainsVariableSpace , JoinConditionWord , etc. Since JS decorators are evaluated at runtime, the engine becomes limited in what static analysis it can do for compilation. |
19:39 | <rbuckton> | i.e., in F# you can do:
query {
for student in db.Student do
groupBy student.Age into g
select (g.Key, g.Count())
}
Which handles into based on whether AllowIntoPattern is set on the groupBy method of the builder.
Or
query {
for student in db.Student do
join selection in db.CourseSelection
on (student.StudentID = selection.StudentID)
select (student, selection)
}
Which parses on as the join condition because it's specified by JoinConditionWord .
|
19:44 | <rbuckton> | F# made this much more customizable than C#, which has explicit syntax for group , join , into , on , select , etc. To do this in JS could mean parsing arbitrary patterns of identifiers and expressions and then enforcing them after the fact:
CoverComputationJoinLikeStatement:
Identifier BindingIdentifier `in` LeftHandSideExpression Identifier LeftHandSideExpression
Where the first Identifier has to match a custom operation keyword, and the 2nd Identifier has to match that operation's JoinConditionWord . Its a level of complexity that I think many would balk at
|
19:51 | <rbuckton> | Plus I'm not sure this would fit well with existing JS expressions/statements...
@query do {
for (const student of db.Student) {
join (const selection of db.Selection on student.studentId === selection.studentId) {
select #[student, selection];
}
}
}
// or
@query do {
for (const student of db.Student)
join (const selection of db.Selection on student.studentId === selection.studentId)
select #[student, selection]
}
|
20:18 | <jschoi> | F# made this much more customizable than C#, which has explicit syntax for group , join , into , on , select , etc. To do this in JS could mean parsing arbitrary patterns of identifiers and expressions and then enforcing them after the fact:
CoverComputationJoinLikeStatement:
Identifier BindingIdentifier `in` LeftHandSideExpression Identifier LeftHandSideExpression
Where the first Identifier has to match a custom operation keyword, and the 2nd Identifier has to match that operation's JoinConditionWord . Its a level of complexity that I think many would balk at
I suppose—if we did do custom keywords in context blocks, and that’s a big if—we could also force them to use a sigil prefix too. |
20:19 | <jschoi> | I think that LINQ blocks probably could still be usable without custom keywords anyway. |
20:23 | <rbuckton> | I have a hard time justifying the value without features like join , group , orderby , etc. |