Ceylon: Awesome Tea or a New Language to Learn

 Awesome Tea or a New Language on OpenShift

Today we will take a look at the Ceylon language. This blog post is not supposed to be a comprehensive guide and doesn’t try to explain everything. The goal is to introduce you to a language that for me, seems to be extremely interesting and not getting the attention it should – my personal opinion.

Ceylon vs. Dart

Ceylon is a new programming language created by JBoss (lead by Gavin King, the inventor of Hibernate), which is part of Red Hat. Ceylon is a compiled language that runs (compiles to) JVM or JavaScript. In this regard, it is similar to Google’s Dart. What is interesting though, is that to run Dart you need a special virtual machine – an environment that manages your program. Compare this to Ceylon that compiles to JVM bytecode, that is much more common than custom VM for Dart. Both languages compile also to JavaScript and can be used for building both server-side back-ends and JavaScript based front-ends.

Why Ceylon?

Ceylon claims many interesting features – but to start, this is a definition you see on the homepage:

Ceylon is a language for writing large programs in teams.

Bold statement – but it doesn’t end here, the claims continue. The homepage says Ceylon is Powerful, Readable, Predictable and provides a Platform, Modularity and Tooling. Let’s take a look at some of Ceylon’s features. But first we need to install Ceylon.

Installing Ceylon

Navigate to the download page and follow the steps mentioned there, based on your own platform. I use Fedora, so I downloaded the RPM package

and then installed it using rpm

sudo rpm -i ceylon.rpm

Now you can run the Ceylon command-line tool. To see if we actually do have Ceylon installed, let’s run

ceylon --version

and you should see something like this

ceylon version 1.0.0 (No More Mr Nice Guy)

Hello, World!

Ceylon inherits syntax from Java. If you have experience with Java already, Ceylon should be pretty familiar to you. Let’s take a look at a simple Ceylon problem

void hello() {  
    print("Hello, World!");   
}

Very basic example, the most common know Hello, world! program. Save the content into some file in source directory. I have used test.ceylon

.
`-- source
    `-- test.ceylon

Now we can try to compile the program either to Java (compile) or to JavaScript (compile-js).

ceylon compile source/test.ceylon

which will print a notification

# Note: Created module default

and finally run the program

ceylon run --run hello default

we use the Ceylon tool to run hello (method name we defined) in a default module (notified it was created for us) and we will see the expected result

Hello, World!

You might have noticed that the file name of the source file was not very important to running the program, so let’s take a look into modularity.

Ceylon’s Modularity

Ceylon takes an interesting attitude to modularity. First, we need to see what packages are. Packages are similar to packages as we know them from Java. Ceylon, however, simplifies the concept. You do define the package by putting the file into a relative path – same as Java. However, you do not need to use the “package some.long.path.here” clause, this is implicitly calculated from the path of the file.

You do need to use the import statement to import classes from other packages. Ceylon will not allow you to use the full class name. Every class needs to be imported first to be available to use. Let’s take a look at a code example

import com.redhat.polar.core { PolarCoord=Polar }

In the example, we import PolarCoord from com.redhat.polar.core and we rename it to Polar for the scope of the current file. Renaming classes allows you to handle clashes of names in the import statements.

Something that is different from what we know from Java are modules. You can think of modules like a combination of packages, jars and maven. Ceylon has built-in support for packaging as well as distribution. This allows elegant management of dependencies. But it’s not only that, modules also form new levels of visibility for your code. Do you remember the time when you needed to have something more visible than a package, but also not visible to everyone? Modules are the answer.

By default, all packages in a module are visible only inside that module. In case you want to make it visible outside, you need to explicitly declare it to be so. In other words, your code is private by default and you explicitly make visible those parts that are supposed to be publicly facing.

Let’s take a look at a simple module descriptor. It would be placed in a file called module.ceylon along with your source-code.

"The best-ever ORM solution!"
license "http://www.gnu.org/licenses/lgpl.html"
module org.hibernate "3.0.0.beta" {
    import ceylon.collection "1.0.0";
    import java.base "7";
    shared import java.jdbc "7";
}

In the example we define new module “org.hibernate” in version “3.0.0.beta” and for the code in the module we import Ceylon.collection and java.base. If some other module imports our module, Ceylon will not make these modules available to it. However java.jdbc will be available inside our module and also in all modules that do import our module. The file-location would be something like src/ceylon/org/hibernate/module.ceylon (however, this depends on your directory structure.)

Ceylon Herd

Herd is the module system repository for Ceylon libraries. The repository separates libraries for Ceylon Java development and Ceylon JavaScript development. When compatible, libraries may be shared for both. Herd provides a centralized way to manage libraries for building applications.

Optional types

An interesting feature is optional types. Often you have the problem with null values. If you do develop in Java, there is NullPointerException and you surely know what kind of problems it may cause. Ceylon does actually bring a feature on the compiler level to help with this issue. Take a look at this snippet:

String name = null; //compile error: null is not an instance of String

So as you can see, when you try to assign null to String, you get a compile-time error. Well, that’s nice, but null is needed sometimes, how could we live without it? In case you need nulled values, you can use so-called Optional Type

String? name = null; // Just fine

At this time, you have something like String and it may contain a null value. What’s the point here? How does that help? Now I have String or null … and it can still fail … and we have to add the question mark there. No use! Au contraire!

The underlying idea is that you are not allowed to call String methods on String? Let’s take a look at this example

String test1 = "ab";
String? test2 = "ab"; 
 
test1.reversed; // transforms the String into "ba"
test2.reversed; // fails, you can not call String methods on nulled String

Hmm, we are getting somewhere now. But still, not being able to use the object, what’s the benefit of having it, right? I agree, there is not much use in it. But what I can do is to check on the value if it exists and use it then. Again, example FTW

String? test = "ab";
if(exists test){
  test.reversed; // works just fine, transofrms to "ba"
}

Using the exists clause – for the body of the block – it virtually removes the “?” if the value is not null … i.e. if the String? test is not null, in the block it is being seen as a simple String. And this way – at compile time – we ensured our application will not fail on a NullPointerException error.

You can read more about this and the other underlying type features in the official documentation.

Deploying to OpenShift

I hope I managed to get you excited about all the Ceylon features. Now it’s time to deploy it on OpenShift. There is an OpenShift cartridge for Ceylon, so starting with it should be fairly simple

rhc app create ceylon https://raw.github.com/matejonnet/openshift-cartridge-ceylon/master/metadata/manifest.yml

Wooohooo, we have Ceylon deployed on OpenShift and you can start developing your new ground-breaking disruption using Ceylon!

Conclusion

Even though Google made me curious about Dart language, I came to the conclusion that Ceylon is more interesting for me. Primarily because the VM underneath Dart is not as flexible as the JVM. Ceylon brings the two worlds of server-side-development and front-end-development together, while Dart seems to be more of a better way to write a JavaScript application. (again, my own point of view, judge yourself for your own use-case).

In the follow-up to this post, we will take a more comprehensive look into Ceylon deployments on OpenShift.

Attribution

Code samples are taken from official documentation. Also, to form the blog post, I have spent a lot in the docs.

I do encourage you to take a look at the documentation.

Next Steps

Categories
JBoss
Tags
, , , ,
Comments are closed.