Ceylon: True advance, or just another language?

Object-oriented and functional programming for the masses

The language road in computer science is littered with the carcasses of what was to be "the next big thing." And although many niche languages do find some adoption in scripting or specialized applications, C (and its derivatives) and the Java language are difficult to displace. But Red Hat's Ceylon appears to be an interesting combination of language features, using a well-known C-style syntax but with support for object orientation and useful functional aspects in addition to an emphasis on being succinct. Explore Ceylon and find out if this future VM language can find a place in enterprise software development. Update: The fail block is clarified in Listing 7. -Ed.

M. Tim Jones, Platform Architect, Intel

author photo - M. Tim JonesM. Tim Jones is an embedded firmware architect and the author of Artificial Intelligence: A Systems Approach, GNU/Linux Application Programming (now in its second edition), AI Application Programming (in its second edition), and BSD Sockets Programming from a Multilanguage Perspective. His engineering background ranges from the development of kernels for geosynchronous spacecraft to embedded systems architecture and networking protocols development. Tim works at Intel and resides in Longmont, Colorado.



07 July 2011 (First published 21 June 2011)

Also available in Chinese Russian Japanese Spanish

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.

Ceylon isn't Java

"Ceylon isn't Java, it's a new language that's deeply influenced by Java, designed by people who are unapologetic fans of Java. Java's not dying anytime soon, so nothing's killing it." —Gavin King

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 zero
  • Integer. Signed integers
  • Float. Floating point
  • Whole. Arbitrary precision signed integers
  • Decimal. 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

Fail or else

As you can see from the reader comments below, language features are actively being debated. The fail block as described here is a result of not prematurely breaking from the loop. An alternative being explored is the use of else rather than fail to indicate that it's the alternate portion of the loop as a decision block.

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.

Resources

Learn

Get products and technologies

  • Evaluate IBM products in the way that suits you best: Download a product trial, try a product online, use a product in a cloud environment, or spend a few hours in the SOA Sandbox learning how to implement Service Oriented Architecture efficiently.

Discuss

  • Get involved in the My developerWorks community. Connect with other developerWorks users while exploring the developer-driven blogs, forums, groups, and wikis.

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Linux on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Linux, Open source
ArticleID=681860
ArticleTitle=Ceylon: True advance, or just another language?
publish-date=07072011