Sometimes it’s easy to forget how much Grace has changed over the last five years. Most of the major language design decisions were made early, and since then … what?
Quite a lot, actually! I just had cause to re-visit some binary tree code that I wrote in the summer of 2015 as an example for a data structures class. It’s nothing special, but does illustrate the power of Grace’s λ-expressions, which, unlike those in Java, let you close over variables, not just constants. We can therefore use a λ-expressions to abstract over the command that is required to update a field in a parent node to refer to a new child. I described this “trick” in a previous post on this blog.
Of course, the original code no longer compiled; too much has changed. What exactly? Comparing the two versions in git gives us a good summary:
- The “math” module has been removed. Mathematical operations are now methods on numbers.
- The “random” module has been added, to give access to various random number generators.
- factory method has been replaced by class.
- Type parameters are now enclosed in double square brackets, rather than in angle brackets.
- Interfaces are defined with the reserved word interface, rather than with type
- inherits has been changed to inherit
- The standard dialect now defines Proceduren and Functionn instead of Blockn
- Traits have been added to Grace, and the standard dialect redefined using them. This makes it possible to combine and re-combine dialects, and pieces of dialects.
- The
==
operator is no longer defined ongraceObject
and inherited by all other objects. Instead,graceObject
definesisMe(_)
andmyIdentityHash
, and a traitidentityEquality
is available for reuse to define the==
,≠
andhash
methods. - Patterns and types are somewhat less confused than formerly. Arbitrary patterns can be used in match statements, but not in type declarations.
- We have rigorously defined Grace’s indentation rules, and minigrace is a bit pickier about correct indentation that it used to be.
- Square brackets now denote Sequence constructors. ”Lineups”, are gone, collections now understand
>>
and<<
for pipelining. - Variable-arity methods are no longer part of Grace. Instead, the programmer can define independent methods with the same name and different numbers of arguments—so
sequence
,sequence(_)
, andsequence(_,_)
can co-exist.
There are probably some other language changes too, and certainly additions to the libraries, but these are the changes that made it necessary to modify formerly-correct code from 2015 so that it compiles and runs in 2020.
The last change—eliminating variable-arity methods—although small in itself, is probably the change with the biggest consequences, because it necessitated changing the interface for constructing collections.
All of these changes have a rationale. In some cases, the change was made for consistency, in others, to make Grace easier to teach. In the case of trait use, it was to make reuse simpler and more powerful than was possible with inheritance alone. Grace continues to evolve, but I feel that we are converging on a language that is pleasant to use, communicates well, and has as much expressiveness (in its target space) as its competitors.