This is a slippery slope. Early versions of Dart tried to use rational numbers by default, but then it was cancelled because denominator size can grow exponentially.
Also, I seriously doubt you can make a language that will correctly resolve checks like this one:
I've used rationals by default in Racket/Scheme for literally 3+ decades now. It's fine. Dart is trying to be an industrial-strength language. We're trying to create an awesome initial programming experience. To the beginner, those denominators are nowhere near as much of a problem as "numbers" that don't make sense.
But we draw limits. Did you try the `sin(pi / 6)` example? You'll find that Pyret produces a rather interesting result that is also instructive. (Hint: it will produce neither true nor false.)
I'm a bit dubious that magic stuff like this really makes anything easier. It's like JavaScript's truthiness and type coersion. It's trying to be friendly and work most of the time, but in reality it is more complex because now you have to remember a whole set of rules about how exactly the magic behaves.
I found it to be a very refreshing and intuitively-guiding experience :)
---
Spoiler alert!
So, fist i had to find how to access pi and sin(), which was simple enough googling for documentation. Typing `num-sin(PI / 6)` on he editor already gives an interesting result:
~0.49999999999999994
That ~ there looks suspicious!
Then i tried `num-sin(PI / 6) == 1 / 2`, which seems to be syntactically invalid and yields an awesome error message:
Reading this expression errored:
num-sin(PI / 6) == 1 / 2
The == and / operations are at the same grouping level. Add parentheses to group the operations, and make the order of operations clear.
Kudos to the Pyret team for such a nice error message!
So finally, adding those missing parens, `num-sin(PI / 6) == (1 / 2)`, yields another informative and useful error message:
Attempted to compare a Roughnum to an Exactnum for equality, which is not allowed:
The left side was:
~0.49999999999999994
The right side was:
0.5
Consider using the within function to compare them instead.
All in all, i'm very impressed with the clarity and approachability of the language. Thanks @skrishnamurthi for the suggestion of trying this out! :D
What's the point of an infix syntax that demands obvious. unnnecessary parentheses, as a matter of correctness?
"grouping level" is a cringe-inducing dumbing down of proper terminology. It suggests associativity, but associativity does not have levels. It must be referring to "precedence".
= and / are not at the same level of precedence in basic mathematics!
In elementary school you learn
y = x / 2
without requiring parentheses.
It makes sense to require parentheses when exotic, unfamiliar operators are involved for which the precedence and associativity would be hard to remember.
Not for operators drilled into your head by sixth grade.
Waaaay less magic than Javascript. Looks like the rules are described here. Two kinds of numbers: exact and rough. Unless you use trig functions it will all be exact. https://www.pyret.org/docs/latest/numbers.html
Fun fact about Javascript: there are string and number constants x, y, and z, such that `x < y` and `y < z` and `z < x`. No NaN shenanigans, just regular small strings and numbers. Hint: it involves a string containing digits that starts with "0", thus sometimes getting implicitly coerced to octal.
Yes, I should have written "practical programming language". It definitely possible to resolve many equations like this (though not all of them), but is quite a slow process, which is ok for a math system like Mathematica, but not for a real-life programming language.
"Real-life programming language" or "practical programming language" assumes that there's only one acceptable set of trade-offs for all "real-life" or "practical" problems. I suspect that what you actually meant was "a programming language designed to create industrial-strength consumer or business software".
As one of the maintainers has noted repeatedly on this thread, Pyret is a "real-life programming language" whose purpose is educational. Mathematica is a "real-life programming language" whose purpose is solving math equations. Performance isn't much of an issue in either case, so it's a perfectly acceptable trade-off.
That these languages weren't designed with your use case in mind doesn't make them illegitimate or inferior languages.
I ran into this issue once while trying to render the Mandelbrot set while learning Haskell. It defaulted to a rational type based on two bignum integers with unlimited precision.
With every Mandelbrot iteration* the integers doubled in size, producing exponential complexity. With 100 iterations this essentially means that the program never completes and even runs out of memory at some point.
The newbie-friendly feature turned out to be not so friendly.
> Early versions of Dart tried to use rational numbers by default, but then it was cancelled because denominator size can grow exponentially.
While I'm generally in favor of rational numbers as a default and believe that its "danger" is no different from that of big integers, there is some truth in this because Guido van Rossum of the Python fame has said the same thing [1]. It seems that you need some adjustments if you are already familiar to languages where rational numbers are not default.
This is a slippery slope. Early versions of Dart tried to use rational numbers by default, but then it was cancelled because denominator size can grow exponentially.
Also, I seriously doubt you can make a language that will correctly resolve checks like this one:
sin(pi / 6) == 1 / 2