Ceylon: True advance, or just another language?
Object-oriented and functional programming for the masses
Linux and open source are commonly associated with the cutting edge of language design. It may be the available tools that support language development or the openness of the platform that gives rise to the advancement of language design. Or perhaps it's that open languages (such as the GNU Compiler Collection family, Ruby, Python, and Perl) based on open source technologies are great because they invite and encourage experimentation and use (not to mention that Red Hat is the company behind Ceylon). For whatever reason, Linux developers have access to a wide range of languages, from the lesser-used historical languages to the newest, cutting-edge offerings.
But in a world of C/C++, the Java™ language, Scala, Ruby, Python, Perl, Erlang, Lua, Scheme, and so many others, should we care about the announcement of a new language focused on business-oriented enterprise software development? In many cases, the answer is no, but let's explore Red Hat's future language offering, called Ceylon, to see whether it can rise to the ranks of today's most popular languages.
Introducing Ceylon
Ceylon is a new project out of Red Hat led by Gavin King. King is the founder of the Hibernate project, a persistence solution within the Java language. Although King is a fan of Java technology—it was one of the first languages suitable for large-scale development—he is quoted as having a number of frustrations with the language (including language complexities like generics, the hastily designed and obscure Standard Edition SDK, a clumsy annotation syntax, broken block structure, dependence on XML, and more).
So, King asked the question, what would a language look like with the lessons learned from the advantages and disadvantages of the Java language and SDK? His answer is Ceylon, a statically typed language that retains some of the best features of the Java language (and runs on the JVM) but improves on that language's readability, built-in modularity, and the incorporation of functional language features like high-order functions. Ceylon also incorporates features of C and Smalltalk. Much like the Java language, this new language is focused on business computing, but it is also flexible and useful in other domains.
Some have called Ceylon a "Java killer" (perhaps due to questions of the Java language's future), but Ceylon in fact runs on the JVM, so it's an extension of Java technology rather than a replacement. Using the JVM to support execution of Ceylon is an ideal model, because it means that Ceylon (like Java) is portable across the multitude of architectures that currently support the JVM.
Ceylon language features
Most languages today defy a simple categorization and instead represent a variety of programming styles. Ceylon is no different. Ceylon is a statically typed language (which means that type checking is performed at compile time, compared with dynamically type languages such as Lisp, where type checking is performed at run time). Ceylon is an object-oriented language, like the Java language, and also supports higher-order functions (which means that functions can take functions as input or output) with a typical C syntax style. Higher-order functions are not supported directly in the Java language, so this functionality represents a unique difference in the two languages.
Sometimes, however, improvements are more about what a language removes
than what it adds. Ceylon simplifies and removes elements of the Java
language, replacing them with a simpler scheme. One example of a
simplification is the removal of the public
,
protected
, and private
keywords. Instead, Ceylon
simply includes the shared
annotation, which defines which
elements of a class are visible externally. Ceylon also removes the
ability to overload but provides some workarounds for this functionality
(such as defaulted and sequenced parameters) with simpler syntax.
Ceylon includes support for inheritance, sequences (array or list construct), generics, named arguments, and more. It includes features for run time type management (we'll explore an example of this in the next section). The language is under active development, so the final feature set remains open.
Ceylon illustrated
Although at the time of this writing a publicly usable compiler does not yet exist, the structure of the Ceylon language is defined, allowing development of sample applications to explore and reason about its use and readability. This section looks at some sample applications in Ceylon that illustrate its structure.
Hello World
I'll use the "Hello World" program to illustrate the creation of a simple
program to emit a simple text string to the display. The example shown in
Listing 1 shows a top-level method called hello
, which uses
the writeLine
method to emit a string to standard output.
Listing 1. The Hello World program in Ceylon
doc "Hello World Program" by "Gavin King" void hello() { writeLine( "Hello World." ); }
Note also the annotation used for API documentation (similar to tools like
doxygen), which allows you to specify the method and author (the
doc
and by
annotations, respectively).
Ceylon types
Ceylon incorporates a traditional set of types that are implemented as ordinary classes. These types are:
Natural
. Unsigned integers, including zeroInteger
. Signed integersFloat
. Floating pointWhole
. Arbitrary precision signed integersDecimal
. Arbitrary precision and arbitrary scale decimals
By default, the Natural
, Integer
, and
Float
types are 64 bit, but you can annotate them with
small
to specify 32-bit precision.
Ceylon class
As Ceylon is an object-oriented language, you write code using the concept of classes. A class is a type in Ceylon that encapsulates a set of operations (called methods) and state in addition to a definition of how the state is initialized when an object of the class is initialized (the class initializer, similar to the constructor).
A simple class will help you understand Ceylon's approach. Listing 2
provides a simple class for a counter class. Line 2 defines the class with
an optional value, which means that the user can provide it or not, and it
is denoted with the Type? pattern. Instead of a constructor, the
body of the class contains the class initializer. This code defines the
private variable (nothing is visible unless annotated as shared), and then
the initialization logic. You begin by checking to see whether the start
variable exists. If it does, it's used as the initial value for your
count. Your first method, annotated as shared
and therefore
visible externally from the class, defines the incrementer. When called,
this method simply increments your counter.
Finally, you define a getter method that returns the current counter value
to the user and a setter method that sets the current counter value with
one provided by the caller. Note the use of the assign
keyword here to create a variable attribute for setting the counter's
value. In addition to handling constructors differently (code embedded
within the class), there's no deconstructor and no way to implement
multiple constructors (just one of the differences from the Java
language).
Listing 2. Simple class in Ceylon
01 doc "Simple Counting Class" 02 class Counter( Natural? start ) { 03 04 doc "Class Initializer" 05 variable Natural count := 0; 06 if (exists start) { 07 count := start; 09 } 10 11 doc "The incrementer" 12 shared void increment() { 13 count++; 14 } 15 16 doc "The getter" 17 shared Natural currentValue { 18 return count; 19 } 20 21 doc "The setter" 22 shared assign currentValue { 23 count := currentValue; 24 } 25 26 }
With your simple class defined, let's look at how you use the class in
Ceylon. Listing 3 provides a block of code that uses your
Counter
class. It begins with the instantiation of the class
to the cnt
object. Note that there is no new
keyword in Ceylon. With your new Counter
object defined, you
call the increment
method and then emit the
Counter
value using your getter method. Note that the
=
and :=
operators are different in Ceylon: you
use the =
specifier only for immutable values, whereas
variable assignment is performed with the :=
operator.
Listing 3. Using the Counter class
01 Counter cnt = Counter(1); 02 cnt.increment(); 03 writeLine( c.currentValue );
Ceylon encourages the use of immutable attributes whenever possible. This
means that an object is initialized with a value and not reassigned. To
specify that a named value is mutable (can be changed after
initialization), it must be annotated with variable
, as is
shown in Listing 2 at line 5.
One final element to explore is a key difference in control structures in
Ceylon. Note that in many languages, braces ({}
) can be
omitted after a conditional expression, such as if a single
statement
appears:
if (cnt > 10) statement();
Ceylon forbids this syntax and requires that braces be present. This means that the sample code shown above must be written in Ceylon as:
if (cnt > 100) { statement(); }
As this represents one of the most common errors in C
, it's a
welcome addition to force this kind of proper style.
Higher-order functions
Ceylon includes the functional style of programming called first-order
functions. This simply means that functions are treated as
first-class objects and can be used as parameters to functions as well as
be returned from functions. Take the example from King's presentation for
the definition of the repeat
method (see Listing 4). In this
case, it takes two arguments: a Natural
for the number of
times to repeat and a method argument for the function to call. Within the
body of the repeat
method, you simply create a
for
loop (using a range operation) and call the method as
passed as the functional parameter.
Listing 4. Higher-order functions in Ceylon
01 void repeat( Natural times, void hfunction() ) { 02 for (Natural n in 1..times) { 03 hfunction(); 04 } 05 }
Using this method is simple, as shown in line 7 of Listing 5. As shown, the method's name is used without arguments.
Listing 5. Using higher-order functions in Ceylon
01 void sayhello() { 02 writeLine( "Hello World." ); 03 } 04 05 ... 06 07 repeat( 10, sayhello );
Unlike other languages with functional support, Ceylon doesn't support anonymous functions (unnamed functions that appear directly in expressions). It does include support for closures (which are essentially functions that can reference state in another function).
Type narrowing
Ceylon does not include the instanceof
operator found in the
Java language; nor does it include typecasting, as can be found in C.
Instead, Ceylon implements what is called type narrowing, which
is used to test and narrow the type of an object reference in one step.
Consider the following code segment in Listing 6. This code uses a special
(is ... )
construct to test an object reference to a given
type. Once the type is identified, the type-specific method is then used.
This construct is similar to the (exists ...)
construct that
you saw earlier in Listing 2 for optional
parameters.
Listing 6. Type narrowing in Ceylon
01 Object obj = <some object>; 02 03 switch (obj) 04 05 case (is Counter) { 06 obj.increment(); 07 } 08 case (is ComplexCounter) { 09 obj.incrementBy(1); 10 } 11 else { 12 stream.writeLine("Unknown object"); 13 }
Ceylon includes another, similar construct defined as
(nonempty ...)
, which you can apply to sequences (arrays or
lists) to determine whether the sequence contains no elements and
therefore may not have sequence operations applied to it.
Finally, note the syntax for switch
statements in Ceylon,
which differs from both C and the Java language. Where those two languages
can be error prone, Ceylon forces a block structure on the cases and
removes the default
case in preference to an
else
block. Ceylon also ensures (at compile time) that the
switch
statement contains an exhaustive list of instance
tests or, at a minimum, an else
clause to provide complete
coverage. The compiler automatically checks these switch
statements and generates an error if an instance is not covered.
Other control structures
Ceylon implements the traditional if...else
statements, as you
would expect, and also implements the Java language's exception handling
features (try
, catch
, finally
).
Ceylon also creates what is called a fail
block that is used
with for
loops to identify when they do not break
prematurely. Consider the example shown in Listing 7.
Listing 7. Illustrating Ceylon's fail block
01 for (Instrument i in instruments) { 02 if (i.failing()) { 03 break; 04 } 05 } 06 fail { 07 // All instruments are working... 08 }
This is a common design pattern in both C and the Java language and therefore a useful addition to Ceylon.
Ceylon's future
As King has said, Ceylon is a community effort and therefore needs software engineers and testers to help design, build, and validate the language and SDK. This call could encourage feedback from Java language users to help support their migration from that language to Ceylon. King is still somewhat silent on the current status of Ceylon, saying only that a language specification exists as well as ANTLR (Another Tool for Language Recognition) grammar.
Going forward
Although some may challenge the necessity of a new language, another way to view languages is as a set of tools that can be used to solve problems. Not every language is suitable or ideal for any given problem, but certain languages lend themselves nicely to specific solution domains; therefore, the availability of multiple languages is a blessing, not a curse. Because Ceylon is still under development, it's unknown whether it will find a place in the ranks of popular languages in use today. But the language captures enough interesting features that it will be fun to explore further when it finally appears.
Downloadable resources
Related topics
- Gavin King's original introduction to the Ceylon language can be seen in this 30-minute video titled Introducing the Ceylon Project Video. Two presentations exist for Ceylon from King, including the introductory presentation and one titled The Ceylon Type System, which covers some of its more advanced features.
- Gavin King provides an 11-part series that describes the Ceylon language. As you'll see from the comments on each element of the series, there's a considerable amount of feedback and a dynamic tailoring of the language to remedy issues that are found. You can find this series at King's blog. To participate in the construction of Ceylon, contact Gavin King at gavin at hibernate dot org.
- ANTLR is a language tool and framework that's used to build compilers, interpreters, translators, and recognizers from a grammatical description. ANTLR comes from the University of San Francisco, based on work from Terence Parr.
- This article touched on some of the functional programming features implemented in Ceylon. Check out the introductions of first-class functions, higher-order functions, and closures at Wikipedia.
- In the developerWorks Linux zone, find hundreds of how-to articles and tutorials, as well as downloads, discussion forums, and a wealth of other resources for Linux developers and administrators.
- Start developing with product trials, free downloads, and IBM Bluemix services.
- Follow developerWorks on Twitter.