Grace has three types of built-in objects: Booleans, Strings, and Rationals, the latter being exact. Grace will also support approximate IEEE 64-bit floating point numbers: particular implementations may support many other types of numbers. All numeric types will be sub-types of an abstract type Number.
The need for exact computation should be obvious to anyone who has tried to explain to a novice why 1/3 * 3 isn’t 1. Once ordinary arithmetic operations are exact, we don’t see a need for separate Natural or Integer types — Javascript and (early) Basic get by quite fine with only one numeric type – floating point numbers. And we don’t see how to eliminate inexact numbers, since operations like square root and sin are going to introduce them again.
Our concern is to minimize the basic types people need to learn: we shouldn’t have to teach the difference between integers & rationals & reals & inexact numbers on day 1. At some point it is important to teach these differences: in the design of Grace we want to support different pedagogical approaches to when this must be taught.
These names illustrate another (minor) design decision: Grace type names are spelled-out in full, rather than being abbreviated. So we have class Number rather than Num, and Boolean rather than Bool. So, what should we call the floating point type? FloatingPoint is ambiguous, because over time the library is likely to contain many floating point formats. DoublePrecision is rather wordy as well as being archaic; Binary64 is the official IEEE name, is shorter and more descriptive – and horrible for novices!
What does it mean for these objects to be “built in”? It means that there are denotations for them in the language syntax. (This is not true for Binary64s; there are, however, methods to generate Binary64s from other Numbers.) So Booleans in Grace are represented by the global names “true” and “false”, and programmers won’t be able to re-define what those names mean.
Grace will provide the usual operations on Booleans — which will be represented as messages. Binary operations will generally use single symbols, such as “&” for and, and “|” for or. We don’t think that the syntax will allow single-symbol unary operators, so Boolean negation will be the named message “not”.
Unlike C, Python, or Groovy, Grace supports no implicit conversions, so Numbers, Strings, Objects, or any other type cannot be used in contexts where Booleans are expected. Rather, Grace programs must explicitly test for empty Strings, Lists, and so on.
String literals in Grace are written between double quotes, as in C, Java, or Python. Strings literals support a range of escape characters such as “\t\b\n\f\r\v\\\””, and also escapes for Unicode.
Like Python, there is no Character type in Grace — rather, characters can be represented by Strings of length 1 where necessary. Like Java, Strings are immutable, and literals may be interned. Grace’s standard library will include mechanisms to support efficient incremental string construction. Strings will also conform to the protocol of an immutable IndexableCollection.
“Hello World!”
“\t”
“The End of the Line\n”
“A”
The Grace type Number is the supertype of all numeric types: we encourage programmers to use this type when writing most programs. Although Grace has no implicit conversions, subtyping means that any numeric type can be stored in a variable or passed as a parameter or return value of type Number.
Grace has three forms of Number literal: ordinary strings of digits, assumed to represent decimal (radix-10) numbers; literals with an explicit radix, indicated by a (decimal) number between 2 and 35 and a leading x; and base-exponent numerals using e as the exponent indicator, also always in decimal. All numeric literals evaluate to exact Rational numbers, so 0.2 will be exactly 1/5. So, there are no literals for inexact numbers.
1
-1
42
3.14159265
13.343e-12
-414.45e3
16xF00F00
2×10110100
0xDEADBEEF // Radix zero treated as 16
Grace will support all the usual binary arithmetic operators. However, as mentioned above, we are currently planning on not allowing unary operator symbols, so negation will be the named method “negative”. (Similarly, the Boolean “not” operator is another message send).
Messages sent to numbers support explicit conversions between number types; for example, sending the message “b64” to any Number will convert it to the 64 bit binary floating point.
Grace’s libraries may support a range of additional numeric types, such as machine integers, bytes, longer and shorter floating point numbers, and complex numbers. These types don’t need to be built-in: one of our design goals is to make library classes as convenient to use as built-in classes, so not being built-in does not mean that they are “second-class” in any way. These additional Number classes are likely to be required in some programs for efficiency, for calling external libraries, or for accessing external data formats. The aim of this design is to present beginners with well-behaved Numbers (and Booleans and Strings), while allowing their instructors to introduce more specialised subclasses as they are needed.
The plan is that most classes in the libraries will accept Numbers as arguments; for example, Indexed Collections, such as Arrays and Strings, will accept Number arguments describing string positions, but will raise an error if the index is not an integer, just as it will if the index is out of bounds.
Grace will have mechanisms (like Java’s final, Scala’s case classes or Lime’s extendedby) that will indicate that classes or interfaces may not be further extended – this should support special case code generation for efficiency.
For the hardcore, here is the BNF for numberLiterals:
numberLiteral ::= [-][radix x][digits][.digits] | [digits][.digits][e][-][digits]
radix ::= 0 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 23 | 33 | 34 | 35
digits :: = digit | digit digits
digit :: = 0 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | y | z
No complaints here, but I do think integer division (5/2==2)is a useful/common concept even for novices and that it’s not very difficult to teach. “I have this operator that given two integers produces an integer. To get that to work, the rule is that you throw away the remainder. Turns out this is useful as we’ll see, but if it’s not what you want you have other options.”
So, no big deal: Grace’s / is exact (producing a Rational). And surely there will be a floor method defined in Number, so we regain integer division via (e1/e2).floor. So now it’s just a question of whether that’s convenient enough or if you want a distinct operator for integer division.
As an example of, yes, integer division is what you want, think of binary search over an array. Or mergesort.
It might be useful to define “div” as an integer style division with “%” as remainder. They are different enough that no one will use them by accident, but they can be introduced when needed with little overhead.
Right. The key points are that you can talk about “integer division” or “truncating division” or a /- operator that works on Numbers without having to talk about a machine-level distinction between “ints” and “floats” and so on; and that you get this with an explicit operation (like div or floor) rather than as the side effect of an assignment or converstion from float to int.
Hmm thinking about that independence more, I can see reasons for Collections to truncate Numbers to Integers on accessors. But, again, perhaps that can be implemented in the library (if there is some way to override the class of Collection “literals”)
I should have added: and stay tuned for the next post, on operator messages…
“Unlike C, Python, or Groovy, Grace supports no implicit conversions, so Numbers, Strings, Objects, or any other type cannot be used in contexts where Booleans are expected.”
This is great. Implicit boolean conversions cause great confusion with my intro. programming students. In particular, they have a lot of trouble understanding why (x == 1 || 2) doesn’t do what they think
why (x == 1 || 2) doesn’t do what they think
yes, we think so too…
Forgive the nitpicking, but it seems that the BNF for numberLiteral allows the empty string as a number, because everything is optional (in both alternatives). In the 2nd alternative, e can be made mandatory, but the first one may have to be split (??)
Forgive the nitpicking…
no problem – you’re right. But as you put it I think it can easily be fixed.
The question is should we permit “.5” as well as “0.5” ?