Interesting consequence of current parsing rules
- Dominant language
- JavaScript
- Stars
- 15.1k
- Forks
- 1.3k
- PR merge metrics
- No merged PRs in 30d
Description
**Q:** Without typing it into the mathjs.org REPL, what type is passed as the argument to `not` in
`math.evaluate('not(sparse([[1, 1]])).valueOf()')`
and what is the result of
`math.evaluate('typeOf(sparse([[1, 1]])).valueOf()')`
???
**A:** Turns out that in the first case, the type is Array, whereas in the second, it's SparseMatrix. In other words, the first expression is parsed as `not( (sparse([[1, 1]])).valueOf() )` whereas the second is parsed as `(typeOf(sparse([[1, 1]]))) .valueOf()`, even though they look syntactically identical. (This difference led to a bug in a mathjs expression that took me a couple of hours to figure out, unfortunately.) The difference it seems stems entirely from the arbitrary designation that `not` is a unary operator, as opposed to `typeOf` that is designated as a unary function (even though, for example, in JavaScript `typeof` is an operator).
I've suggested before that this distinction between unary operators and functions is artificial and has no benefit and that the expression language would be improved by eliminating it. I am not posting particularly to reopen that debate. I think the important thing for now is that when an operator is used with function-style syntax `not(expr)` it should parse/behave like a function, just as `and(exprA, exprB)` does. Otherwise, it's just too difficult to read and write expressions, having to remember special rules for just a small handful of specific symbols. I would suggest that the current non-parallelism between `not` and `typeOf` amounts to something at least very close to bug, and would suggest it be addressed in one or more of the following ways:
I) Just make `not` a unary function. The only side effect is that with no other changes to the parser, the expression `not true` would become illegal, and one would have to write `not(true)`.
II) Allow any unary function (e.g., `sin`) to apply to the following expression like `not` does now (i.e., in essence make all unary functions into unary operators). I know @josdejong has had concerns about this in the past; I am merely including it here to record the logical possibilities I can think of.
III) Alter the parser so that when a function or operator is used with unary function-call notation, `OP(EXPR)`, then it parses just like a unary function call, with the same precedence and grouping, etc.
IV) Try for a one-off fix for the specific troublesome expressions noted above, e,g., try making the `not` operator higher-precedence than the `.` accessor operator, so that `not S.method()` always parses as `(not S).method()` rather than `not (S.method())`, even without any parentheses, This precedence change would be at odds with JavaScript, where `!object.method()` means `!(object.method())` rather than `(!object).method()`.
V) Do nothing except document the difference between a unary function and a unary operator even more clearly, with a specific warning about the pitfall of this parsing difference between the two.
There may of course be other options I haven't thought of., and clearly I am not a fan of (V). But please just let me know what direction you'd like to go in connection with the potential difficulty highlighted here and I will file a PR as soon as I can.
Contributor guide
Assessment
This issue has not been assessed yet.