Note: information on this page refers to Ceylon 1.0, not to the
current release.

Basics

Let's get started!

Before we can get into any of the really interesting and powerful features of
this language, we need to get comfortable with some of the basic syntax, so
we'll know what we're looking at later on, when we get up to the really good
stuff.

Note that because the second line of the string literal contained whitespace
right up until the first character of the first line of the string literal,
all that whitespace was automatically removed. This helps us format our
code nicely.

It's often useful to collapse whitespace in a multiline string literal. The
String
class has an attribute called
normalized.
We can use it like this:

The doc, by, see, throws, and tagged annotations contain documentation
that is included in the output of the Ceylon documentation compiler,
ceylon doc.

Annotations like doc, by, see, and throws, aren't keywords. They're
just ordinary identifiers. The same is true for annotations which are part of
the language definition, for example: abstract, variable, shared, formal,
default, actual, etc. This is quite different to other C-like languages. (On
the other hand, voidis a keyword, just like in C or Java.)

Since the doc annotation is ubiquitous, its name and parentheses may be left
out whenever it occurs as the first annotation in the list of annotations of a
program element:

Formatting inline documentation

"The classic [Hello World program][helloworld]
that prints a message to the console, this
time written in [Ceylon][].
This simple program demonstrates:
1. how to define a toplevel function, and
2. how to `print()` a literal `String`.
You can compile and run `hello()` from the
command line like this:
ceylon compile source/hello.ceylon
ceylon run -run hello default
Or you can use `Run As > Ceylon Application`
in the IDE.
[helloworld]: http://en.wikipedia.org/wiki/Hello_world_program
[Ceylon]: http://ceylon-lang.org"
void hello() {
print("Hello, World!");
}

Since Markdown is sensitive to the initial column in which text appears,
you need to be careful to indent the lines of the multiline string literal
correctly, as we've done here.

Escape sequences

Inside a string literal, you can use the escape sequences \n, \t, \\,
\" and friends that you're used to from other C-like languages.

print("\"Hello!\", said the program.");

You can also use 2-byte and 4-byte hexadecimal escape sequences to embed
Unicode characters in your text.

"The mathematical constant \{#03C0}, the
ratio of the circumference of a circle
to its diameter."
Float pi=calculatePi();
"The mathematical constant \{#0001D452},
the base of the natural logarithm."
Float e=calculateE();

Even better, you can identity a Unicode character by its name.

"The mathematical constant \{GREEK SMALL LETTER PI}, the
ratio of the circumference of a circle to its diameter."
Float pi=calculatePi();
"The mathematical constant \{MATHEMATICAL ITALIC SMALL E},
the base of the natural logarithm."
Float e=calculateE();

Verbatim strings

Sometimes, escape sequence interpolation is annoying, for example, when
embedding code in a string literal. If we use three double-quotes, """,
to delimit our string, we get a verbatim string, which may contain
unescaped backslash and double-quote characters:

print(""""Hello!", said the program.""");

String interpolation and concatenation

Let's make our program tell us a little more about itself.

"The Hello World program ... version 1.1!"
void hello() {
print("Hello, this is Ceylon ``language.version``
running on Java ``runtime.version``!\n
You ran me at ``system.milliseconds`` ms,
with ``process.arguments.size`` arguments.");
}

Notice how our message contains interpolated expressions, delimited using
"doublebacks", that is, two backticks. This is called a string template.

On my machine, this program results in the following output:

Hello, this is Ceylon 1.0.0
running on Java 1.7!
You ran me at 1362763185067 ms,
with 0 arguments.

The + operator you're probably used to is an alternative way to concatenate
strings, and more flexible in many cases:

Note that when we use + to concatenate strings, we have to explicitly
invoke the
string
attribute to convert numeric expressions to strings. The
+ operator does not automatically convert its operands to strings, so the
following does not compile:

Dealing with objects that aren't there

Let's take a name as input from the command line. We have to account for
the case where nothing was specified at the command line, which gives us
an opportunity to explore how null values are treated in Ceylon, which
is quite different to what you're probably used to in Java or C#.

Let's consider an overly-verbose example to start with. (We'll work our
way up to a more convenient form.)

This is the preferred style most of the time, since we can't actually use
name for anything useful outside of the if (exists ... ) construct.
(But this still isn't the most compact way to write this code.)

Optional types

Local variables, parameters, and attributes that may contain null values
must be explicitly declared as being of optional type (the T? syntax).
There's simply no way to assign null to a local that isn't of optional type.
The compiler won't let you. This is an error:

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

Nor will the Ceylon compiler let you do anything dangerous with a value of
type T? - that is, anything that could cause a NullPointerException in
Java - without first checking that the value is not null using
if (exists ... ). The following is also an error:

String? name = process.arguments.first;
print("Hello " + name + "!"); //compile error: name is not Summable

In fact, it's not even possible to use the equality operator == with an
expression of optional type. We can't write:

String? name = process.arguments.first;
if (name==null) { ... } //compile error: name is not Object

like we can in Java. This helps avoid the undesirable behavior of == in
Java where x==y evaluates to true if x and y both evaluate to null.

In a language with static typing, we're always wanting to know what the type
of something is. So what's the type of null?

Yes, that's right: the value null isn't a primitive value in Ceylon, it's
just a perfectly ordinary instance of the perfectly ordinary class Null,
at least from the point of view of Ceylon's type system.

And the syntax String? is just an abbreviation for the
union typeNull|String.

That's why we can't call operations of String on a String?. It's simply
a different type! The if (exists ...) construct narrowed the type of name
inside the if block, allowing us to treat name as a String there.

(As an aside, if you're concerned about performance, it's worth mentioning that
the Ceylon compiler does some special magic to transform this value to a virtual
machine-level null, all under the covers.)

Operators for handling null values

There are a couple of operators that will make your life easier when dealing
with null values. The first is else:

String greeting = "Hello, " + (name else "World");

The else operator produces:

its first operand if the first operand is not null, or

its second operand otherwise.

It's a more convenient way to handle null values in simple cases. You
can chain multiple elses:

String name = firstName else userId else "Guest";

There's also an operator for producing a null value:

String? name = !arg.trimmed.empty then arg;

The then operator produces

its second operand if its first operand evaluates to true, or

null otherwise.

You can chain an else after a then to reproduce the behavior of C's
ternary ?: operator:

String name = !arg.trimmed.empty then arg else "World";

If we need to squeeze a whole chain of thens/elses into a single
expression, we can use the "poorman's switch" idiom:

Functions and values

The two most basic constructs found in almost every programming language
are functions and variables. In Ceylon, "variables" are, by default,
assignable exactly once. That is, they can't be assigned a new value after
an initial value has been assigned. Therefore, we use the word value to
talk about "variables" collectively, and reserve the word variable to
mean a value which is explicitly defined to be reassignable.

Note that even a value which isn't a variable in this sense, may still be
"variable" in the sense that its value varies between different runs of
the program, or between contexts within a single execution of the program.

A value may even be recalculated every time it is evaluated.

String name { return firstName + " " + lastName; }

If the values of firstName and lastName vary, then the value of
name also varies between evaluations.

A function takes this idea one step further. The value of a function
depends not only upon the context in which it is evaluated, but also
upon the arguments to its parameters.

Float sqr(Float x) { return x*x; }

In Ceylon, a value or function declaration can occur almost anywhere:

as a toplevel, belonging directly to a package,

as an attribute or method of a class, or

as a block-local declaration inside a different value or function
body.

Indeed, as we'll see later, a value or function declaration may even
occur inside an expression in some cases.

Functions declarations look pretty similar to what you're probably already
used to from other C-like languages, with two exceptions. Ceylon has:

defaulted parameters, and

variadic parameters.

Defaulted parameters

A function parameter may specify a default value.

void hello(String name="World") {
print("Hello, ``name``!");
}

Then we don't need to specify an argument to the parameter when we call
the function:

hello(); //Hello, World!
hello("JBoss"); //Hello, JBoss!

Defaulted parameters must be declared after all required parameters in the
parameter list of a function.

Variadic parameters

A variadic parameter of a function or class is declared using a postfix
asterisk, for example, String*. There may be only one variadic parameter
for a function or class, and it must be the last parameter.

void helloEveryone(String* names) {
// ...
}

Inside the function body, the parameter names has type [String*], a
sequence type, which we'll learn about later. Thus, we
can iterate the parameter using a for loop to get at the individual
arguments.

Fat arrows and forward declaration

Ceylon's expression syntax is much more powerful than Java's, and it's
therefore possible to express a lot more in a single compact expression.
It's therefore extremely common to encounter functions and values which
simply evaluate and return an expression. So Ceylon lets us abbreviate
such function and value definitions using a "fat arrow", =>. For example:

String name => firstName + " " + lastName;

Or:

Float sqr(Float x) => x*x;

Now's the time to get comfortable with this syntax, because you're going
to be seeing quite a lot of it. Take careful note of the difference between
a fat arrow:

String name => firstName + " " + lastName;

And an assignment:

String name = firstName + " " + lastName;

In the first example, the expression is recomputed every time name is
evaluated. In the second example, the expression is computed once and the
result assigned to name.

We're even allowed to define a void function using a fat arrow. Earlier,
we could have written hello() like this:

void hello() => print("Hello, World!");

In Java and C#, we're allowed to separate the declaration of a variable
from the initialization of its value. We've
already seen that this is also
allowed in Ceylon. So we can write:

The compiler makes sure we don't evaluate a value or invoke a function
before assigning it a value or specifying its implementation, as we'll see
later.
(Because if we did, it would result in a NullPointerException, which
Ceylon doesn't have!)

Numbers

Unfortunately, not every program is as simple and elegant as "hello world".
In business or scientific computing, we often encounter programs that do
fiendishly complicated stuff with numbers. Ceylon doesn't have any primitive
types, so numeric values are usually represented by the classes
Integer
and Float,
which we'll come back to later in the tour.

Float literals are written with a decimal point, and Integer literals
without:

Integer one = 1;
Float zero = 0.0;

Even though they're classes, you can use all the usual numeric literals and
operators with them. For example, the following function efficiently determines
if an Integer represents a prime number: