Ceylon (programming language)

From Bauman National Library
This page was last modified on 1 June 2016, at 17:20.
Ceylon
FileTeplov2.png
Paradigm Imperative, Object-Oriented
Designed by Red Hat
First appeared 2011
Stable release 1.2.0 / 29.10 2015
License Apache License 2.0
Filename extensions .ceylon
Website http://ceylon-lang.org
Influenced by
Java, JavaScript, C#

Ceylon is an imperative programming language aimed at team development of large-scale projects.

The first release of the language, Ceylon M1, was released on December 20th, 2011 and provides about 80% of intended language features[1].

Major design principles of the language:

  • code readability: the value of this increases along with the size of development team[1].
  • predictability: the compiler’s and program’s behavior must be intuitive and easy to be reproduced by the programmer[1].
  • toolability: extensive usage of tools improves programmer’s productivity a lot, and the effect increases along with the scale of the project, so the language should provide a lot of tools, starting with IDE, and have as few features hard for tools to understand as possible[1].
  • modularity: once again, the larger are the programs developed, the more important their organization becomes.
  • metaprogramming: a lot of libraries and complex frameworks are based on the ability to write code which manipulates on other code[1].

The language syntax resembles Java and C# a lot. In fact, Ceylon is largely based on Java, but it aims to inherit successful features and eliminate or fix unsuccessful ones[1].

Contents

Ceylon language features[2]

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 is as an extension or replacement of the Java language

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[2].

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.[2].

Ceylon types[2]

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.

Operators Ceylon

! (not) operator

The right-associative, unary || operator is used to compute the logical not of its operand.

Example

Boolean true_ = !false;

!= (not equal) operator

The non-associating, binary infix != operator is used to test whether its operands are not equal.

Example

void m(Object x, Object y) {
    Boolean identical = x != y;
}

% (remainder) operator

The binary, left-associative infix % operator is used to get the remainder of an integer division. Example

Integer two = 5 % 3;

%= (remainder assign) operator

The right-associative, binary infix %= operator takes the remainder of it's left-hand operand with respect to its right-hand operand and updates the left-hand operand with the result.

Example

variable Integer num = 10;
num %= 2; // half num

& (intersection) operator

The left-associative, binary infix & operator is used to compute the intersection of its operands.

Example

void m(Set<Integer> primes, Set<Integer> evens) {
    Set<Integer> two = primes &amp; evens;
}

&& (and) operator

The left-associative, binary infix && operator is used to compute the logical and of two operands

Example

Boolean false_ = true &amp;&amp; false;

&&= (and assign) operator

The right-associative, binary infix &&= operator is used to compute the logical and of two operands, assigning the result to the left-hand operand.

Example

variable Boolean a = true;
Boolean b = false;
a &amp;&amp;= b; // a becomes false

&= (set intersect assign) operator

The right-associative, binary infix &= operator is used to compute the intersection of two operands, assigning the result to the left-hand operand.

Example

void m(Set<Integer> primes, Set<Integer> evens) {
    variable Set<Integer> two = primes;
    two &amp;= evens;
}

() (invoke) operator

The left-associative, unary () and {} operators are used to invoke methods and instantiate classes.

Example

print("hello, world!");       // positional style
print{                        // named-arguments style
    line="hello, world";
};
MyClass instance = MyClass(); // invoking a class to get an instance

* (product) operator

The left-associative, binary infix * operator is used to compute the product of two operands.

Example

Integer six = 3 * 2;

** (scale) operator

The right-associative, binary infix ** operator is used to scale an instance of Scalable but an amount.

Example

value four_plus_6i = 2 ** Complex(2, 3);

*= (multiply assign) operator

The right-associative, binary infix *= operator multiplies it's left-hand operand by the amount given by its right-hand operand and assigns the result to the left-hand operand.

Example

variable Integer num = 1;
num *= 2; // double num 
num *= num; // square num

+ (sum) operator

The left-associative, binary infix + operator is used to sum two operands.

Example

Integer three = 1 + 2;
String concatenated = "foo" + "bar";

+ (unary plus) operator

The right-associative, unary prefix + operator is used to clarify the positive value of its operand.

Example

Integer one = +1;
Integer minusOne = +(-1);

++ (increment) operator

The left-associative, unary ++ operators increment their operand; they differ in whether the result is assigned before or after the increment.

Example 1

variable Integer num = 1;
num++;

Example 2

variable Integer num = 1;
++num;

+= (add assign) operator

The right-associative, binary infix += operator increments it's left-hand operand by the amount given by its right-hand operand.

Example

variable Integer num = 1;
num += 1; // increment num by 1
num += num; // increment num by 2

-(difference) operator

The left-associative, binary infix - operator is used to take the difference of two operands.

Example

Integer one = 3 - 2;

- (unary minus) operator

The right-associative, unary prefix - operator is used to invert the sign of its operand.

Example

Integer minusOne = -1;

-- (decrement) operator

The left-associative, unary -- operators decrement their operand; they differ in whether the result is assigned before or after the decrement.

Example 1

variable Integer num = 1;
num--;

Example 1

variable Integer num = 1;
--num;

-= (subtract assign) operator

The right-associative, binary infix -= operator decrements it's left-hand operand by the amount given by its right-hand operand.

Example

variable Integer num = 4;
num -= 1; // decrement num by 1
num -= num; // decrement num by 3

-> (entry) operator

The infix entry operator creates an Entry from its key and value.

Example

Entry<Integer, String> intName = 1 -> "One";

. (member) operator

The left-associative, binary infix . operator is used to access the member named by the right-hand operand from left-hand operand.

Example

String[] args = process.arguments;

.. (spanned range) operator

The spanned range operator creates a Range from its endpoints.

Example

Range<Integer> ten = 1..10;

y:z (measured range) operator

The measured range operator creates a Range from a starting point and a length.

Example

Range<Integer> ten = 1:10;

/ (quotient) operator

The left-associative, binary infix / operator is used to compute the quotient of two operands.

Example

Integer three = 6 / 2;

/= (divide assign)operator

The right associative, binary infix /= operator divides it's left-hand operand by the amount given by its right-hand operand.

Example

variable Float num = 1.0;
num /= 2.0; // half num

< (less than) operator

The non-associating, binary infix < operator is used to test whether its left-hand operand is less than its right-hand operand.

Example

void m<T>(T x, T y) 
  given T satisfies Comparable<T> {
    Boolean less = x < y;
}

<= (less than or equal) operator

The non-associating, binary infix <= operator is used to test whether its left-hand operand is less than or equal to its right-hand operand.

Example

void m<T>(T x, T y) 
  given T satisfies Comparable<T> {
    Boolean lessOrEqual = x <= y;
}

<=> (compare) operator

The non-associating, binary infix <=> operator is used to compare the order of its operands.

Example

void m<T>(T x, T y) given T satisfies Comparable<T> {
    Comparison cmp = x <=> y;
}

= (assign) operator

The right-associative, binary infix = operator is used to assign a value to a variable-annotated attribute.

Example

variable Integer num = 1; // assign
num = 2; //assign
Integer three = 3 // specify

== (equal) operator

The non-associating, binary infix == operator is used to test whether its operands are equal.

Example

void m(Object x, Object y) {
    Boolean identical = x == y;
}

=== (identical) operator

The non-associating, binary infix === operator is used to test whether its operands are identica.

Example

void m(Identifiable x, Identifiable y) {
    Boolean identical = x === y;
}

> (greater than) operator

The non-associating, binary infix > operator is used to test whether its left-hand operand is greater than its right-hand operand.

Example

void m<T>(T x, T y) 
  given T satisfies Comparable<T> {
    Boolean more = x > y;
}

>= (greater than or equal) operator

The non-associating, binary infix >= operator is used to test whether its left-hand operand is greater than or equal to its right-hand operand.

Example

void m<T>(T x, T y) 
  given T satisfies Comparable<T> {
    Boolean greaterOrEqual = x >= y;
}

?. (null-safe attribute) operator

The left-associative, binary ?. operator is used to access an attribute as if its right-hand operand were not null.

Example

void m(Integer? num) {
    Integer? int = num?.positiveValue;
}

?. (null-safe method) operator

The left-associative, binary ?. operator is used to invoke a method as if its right-hand operand were not null.

Example

void m(Integer? num) {
    Integer?(Integer) plus = num?.plus;
}

[] (lookup) operator

The lookup operator accesses a particular item in a Correspondence.

Example

void m(Integer[] seq) {
    Integer? first = seq[0];
}

* (spread) operator

The spread operator, produces multiple values by iterating the iterable object to which the spread operator is applied.

Example

void spreadIterable(String* names) {
    // note names is a variadic parameter
}

{String*} names = { "Tom", "Gavin" };

// Invocation using listed arguments
spreadIterable("Tom", "Gavin");

// Invocation using a spread iterable argument
spreadIterable(*names);

*. (spread attribute) operator

The spread attribute operator maps an iterable of instances through an attribute, resulting in a sequence of the attribute values.

Example

{String+} names = {"foo", "bar", "baz"};
{Integer+} sizes = names*.size;

*. (spread method) operator

The spread method operator maps an iterable of instances through a method, resulting in a new sequence containing the return values of each method invocation.

Example

{String+} names = {"foo", "bar", "baz"};
{String+} initials = names*.initial(1);

x[y..z] (span) operator

The span operator returns the subrange of its left-hand operand indexed by its centre and right-hand operands.

Example

String[] names = {"foo", "bar", "baz"};
String[] firstAndSecond = names[0..1];
String[] secondAndThird = names[1..2];

x[y...] (upper span) operator

The upper span operator returns the tail of its left-hand Ranged operand as specified by its right-hand operand.

Example

String[] names = {"foo", "bar", "baz"};
String[] secondAndThird = names[1...];
String[] third = names[2...];
String[] emptySequence = names[3...];

x[...z] (lower span) operator

The lower span operator returns the elements of its left-hand Ranged operand upto and including the element whose key is specified by its right-hand operand.

Example

String[] names = {"foo", "bar", "baz"};
String[] foo = names[...0];
String[] foobar = names[...1];
String[] emptySequence = names[...-1];

x[y:z] (measure) operator

The measure operator returns the subrange of its left-hand operand starting from its central operand and including as many elements as given by its right-hand operand.

Example

String[] names = {"foo", "bar", "baz"};
String[] foo = names[0:1];
String[] barBaz = names[1:2];
String[] empty = names[1:0];

^ (power) operator

The right-associative, binary infix ^ operator is used to compute its left-hand operand raised to the power of its right-hand operand.

Example

Integer eight = 2 ^ 3;

| (Set union) operator

The left-associative, binary infix | operator is used to compute the union of two operands.

Example

void m(Set<Integer> odds, Set<Integer> evens) {
    Set<Integer> ints = odds | evens;
}

|= (Set union assign) operator

The right-associative, binary infix |= operator is used to compute the union of two operands, assigning the result to the left-hand operand

Example

void m(Set<Integer> odds, Set<Integer> evens) {
    variable Set<Integer> all = odds;
    all |= evens;
}

|| (or) operator

The left-associative, binary infix || operator is used to compute the logical or of two operands.

Example

Boolean true_ = true || false;

||= (or assign) operator

The right-associative, binary infix ||= operator is used to compute the logical or of two operands, assigning the result to the left-hand operand.

Example

variable Boolean a = false;
Boolean b = true;
a ||= b; // a becomes true

{} (invoke) operator

The left-associative, unary () and {} operators are used to invoke methods and instantiate classes.

Example

print("hello, world!");       // positional style
print{                        // named-arguments style
    line="hello, world";
};
MyClass instance = MyClass(); // invoking a class to get an instance

~ (Set complement) operator

The left-associative, binary infix ~ operator is used to compute the complement of its left-hand operand in its right-hand operand.

Example

void m<Dog>(Set<Dog> dogs, Set<Dog> blackDogs) 
  given Dog satisfies Object {
    Set<Dog> nonBlackDogs = dogs ~ blackDogs;
}

~= (Set complement assign) operator

The right-associative, binary infix ~= operator is used to compute the complement of its left-hand operand in its right-hand operand, assigning the result to the left-hand operand.

Example

void m<Dog>(Set<Dog> dogs, Set<Dog> blackDogs) 
  given Dog satisfies Object {
    variable Set<Dog> nonBlackDogs = dogs;
    nonBlackDogs ~= blackDogs;
}

else operator

The left-associative, binary else operator is used to provide a default value when it's left operand is null.

Example

void m(Integer? num) {
    Boolean haveNum = num exists;
}

exists operator

The non-associating, unary postfix exists operator is used to test its operand for nullness.

Example

void m(Integer? num) {
    Boolean haveNum = num exists;
}

in operator

The non-associating, binary infix in operator is used to test whether its left-hand operand is contained in its right-hand operand

Example

void m(Object x, Category y) {
    Boolean contained = x in y;
}

is operator

The non-associating, binary infix is operator is used to test the type of an expression

Example

void m(Object? obj) {
    Boolean isNumber = obj is Number<out Anything>;
    Boolean isNull = obj is Null;
}

nonempty operator

The non-associating, unary postfix nonempty operator is used to test its operand for emptiness.

Example

void m(Integer[] nums) {
    Boolean haveNums = nums nonempty;
}

of operator

The non-associating, binary infix of operator is used to cast the type of an expression, when this can be statically proven to be safe.

Example

void m(Anything obj) {
    Object|Null maybeNull = obj of Object|Null;
}

then operator

The left-associative, binary then operator evaluates its right operand only when it's left operand is true, otherwise it evaluates as null.

Example

void m(String s) {
    String s2 = s.empty then "hello";
}

Statements Cyelon

  • assert
  • break
  • continue
  • Condition lists
  • Expression statements
  • for
  • if statement
  • import
  • return
  • Specification statements
  • Destructuring specification
  • switch statement
  • throw
  • try
  • while

Examples

Hello, World!

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

Factorial

This example calculates factorials iteratively. variable keyword points out that the value of the variable fact is going to be changed later (exactly the opposite of Java keyword final). Integer data type allows to store values of factorial without overflow. The arguments of print are concatenated without any explicit operator, but for this the first and the last elements of the list to be concatenated have to be string literals.

void factorial() {
    variable Integer fact := 1;
    for (i in 0..16) {
        print("" i "! = " fact "");
        fact *= i + 1;
    }
}

Fibonacci numbers

This example calculates Fibonacci numbers iteratively.

void fibon() {
    variable String output := "";
    variable Integer fib1 := 0;
    variable Integer fib2 := 1;
    variable Integer fib3;
    for (i in 1..16) {
        output := "" output "" fib2 ", ";
        fib3 := fib1 + fib2;
        fib1 := fib2;
        fib2 := fib3;
    }
    print("" output "...");
}

Ceylon's future [2]

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..[2]

References

  1. 1.0 1.1 1.2 1.3 1.4 1.5 Ceylon
  2. 2.0 2.1 2.2 2.3 2.4 2.5 Ceylon: True advance, or just another language?

External links