Ceylon Language

Embed Size (px)

Citation preview

  • 7/31/2019 Ceylon Language

    1/103

    Ceylon LanguageSource: http://relation.to/tag/Introduction+to+Ceylon

    10/19/2011

  • 7/31/2019 Ceylon Language

    2/103

    2 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    1. BASICS ........................................................................................................................ 5

    ABOUT CEYLON ........................................................................................................................... 5

    WRITING A SIMPLE PROGRAM .......................................................................................................... 5

    ADDING INLINE DOCUMENTATION ..................................................................................................... 7

    STRINGS AND STRING INTERPOLATION................................................................................................. 8

    DEALING WITH OBJECTS THAT AREN'T THERE.......................................................................................... 9

    OPERATORS FOR HANDLING NULL VALUES .......................................................................................... 11

    DEFAULTED PARAMETERS ............................................................................................................. 11

    2. CLASSES AND MEMBERS............................................................................................ 12

    CREATING YOUR OWN CLASSES ....................................................................................................... 12

    HIDING IMPLEMENTATION DETAILS .................................................................................................. 13

    ABSTRACTING STATE USING ATTRIBUTES ............................................................................................ 14

    UNDERSTANDING OBJECT INITIALIZATION ........................................................................................... 15

    INSTANTIATING CLASSES AND OVERLOADING THEIR INITIALIZER PARAMETERS ................................................. 163. INHERITANCE AND INTRODUCTION ........................................................................... 19

    INHERITANCE AND REFINEMENT ...................................................................................................... 19

    ABSTRACT CLASSES ..................................................................................................................... 20

    INTERFACES AND MIXIN INHERITANCE ............................................................................................... 21

    AMBIGUITIES IN MIXIN INHERITANCE ................................................................................................ 23

    INTRODUCTION ......................................................................................................................... 25

    INTRODUCTION COMPARED TO EXTENSION METHODS AND IMPLICIT TYPE CONVERSIONS .................................... 27

    TYPE ALIASES............................................................................................................................ 28

    MEMBER CLASSES AND MEMBER CLASS REFINEMENT.............................................................................. 28

    ANONYMOUS CLASSES ................................................................................................................. 304. SEQUENCES............................................................................................................... 33

    SEQUENCE SYNTAX SUGAR ............................................................................................................ 33

    ITERATING SEQUENCES................................................................................................................. 34

    SEQUENCE AND ITS SUPERTYPES ...................................................................................................... 34

    EMPTY SEQUENCES AND THE BOTTOM TYPE ........................................................................................ 37

    SEQUENCE GOTCHAS FOR JAVA DEVELOPERS........................................................................................ 38

    5. UNIONS, ALGEBRAIC TYPES, AND TYPE INFERENCE .................................................... 41

    NARROWING THE TYPE OF AN OBJECT REFERENCE.................................................................................. 41

    MORE ABOUT UNION TYPES ........................................................................................................... 41

    ENUMERATED SUBTYPES............................................................................................................... 42

    VISITORS................................................................................................................................. 43

    TYPESAFE ENUMERATIONS ............................................................................................................ 45

    TYPE INFERENCE ........................................................................................................................ 47

    TYPE INFERENCE FOR SEQUENCE ENUMERATION EXPRESSIONS ................................................................... 48

    6. GENERICS.................................................................................................................. 49

    DEFINING GENERIC TYPES.............................................................................................................. 49

    COVARIANCE AND CONTRAVARIANCE ................................................................................................ 50

    GENERIC TYPE CONSTRAINTS .......................................................................................................... 53

    7. ATTRIBUTES AND LOCALS, CONTROL STRUCTURES, AND IMPORTS ............................ 57

    ATTRIBUTES AND LOCALS .............................................................................................................. 57

  • 7/31/2019 Ceylon Language

    3/103

    3 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    VARIABLES............................................................................................................................... 58

    SETTERS ................................................................................................................................. 58

    CONTROL STRUCTURES................................................................................................................. 59

    SEQUENCED PARAMETERS............................................................................................................. 61

    PACKAGES AND IMPORTS .............................................................................................................. 61

    8. HIGHER ORDER FUNCTIONS....................................................................................... 63

    FIRST CLASS AND HIGHER ORDER FUNCTIONS ....................................................................................... 63

    REPRESENTING THE TYPE OF A FUNCTION ........................................................................................... 63

    REPRESENTING THE TYPE OF A METHOD ............................................................................................. 64

    DEFINING HIGHER ORDER FUNCTIONS................................................................................................ 65

    FUNCTION REFERENCES ................................................................................................................ 66

    MORE ABOUT HIGHER-ORDER FUNCTIONS .......................................................................................... 67

    9. NAMED ARGUMENTS AND THE BUILDER SYNTAX ...................................................... 72

    NAMED ARGUMENTS .................................................................................................................. 72DECLARATIVE OBJECT INSTANTIATION SYNTAX...................................................................................... 73

    MORE ABOUT NAMED ARGUMENTS.................................................................................................. 74

    DEFINING USER INTERFACES........................................................................................................... 78

    10. BASIC TYPES AND OPERATORS .................................................................................. 80

    AN OVERVIEW OF THE LANGUAGE MODULE ......................................................................................... 80

    EQUALITY AND IDENTITY............................................................................................................... 81

    OPERATOR POLYMORPHISM .......................................................................................................... 82

    THE SLOTS INTERFACE .................................................................................................................. 83

    NUMERIC TYPES......................................................................................................................... 84

    NUMERIC LITERALS ..................................................................................................................... 84NUMERIC WIDENING ................................................................................................................... 85

    NUMERIC OPERATOR SEMANTICS..................................................................................................... 86

    11. INITIALIZATION ......................................................................................................... 88

    SELF REFERENCES AND OUTER INSTANCE REFERENCES ............................................................................. 88

    MULTIPLE INHERITANCE AND LINEARIZATION ....................................................................................... 88

    DEFINITE ASSIGNMENT AND DEFINITE INITIALIZATION ............................................................................. 89

    CLASS BODIES ........................................................................................................................... 90

    INITIALIZER SECTION ................................................................................................................... 91

    DECLARATION SECTION ................................................................................................................ 93

    CIRCULAR REFERENCES................................................................................................................. 94

    DEFINITE INITIALIZATION OF METHODS .............................................................................................. 94

    DEFINITE RETURN....................................................................................................................... 95

    12. ANNOTATIONS AND INTERCEPTORS .......................................................................... 96

    ANNOTATIONS .......................................................................................................................... 96

    ANNOTATION ARGUMENTS ........................................................................................................... 96

    ANNOTATION TYPES.................................................................................................................... 97

    ANNOTATION CONSTRAINTS .......................................................................................................... 98

    READING ANNOTATION VALUES AT RUNTIME ....................................................................................... 99

    DEFINING ANNOTATIONS ............................................................................................................ 100

    INTERCEPTORS ........................................................................................................................ 101

  • 7/31/2019 Ceylon Language

    4/103

    4 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    CONCLUSION .......................................................................................................................... 102

  • 7/31/2019 Ceylon Language

    5/103

    5 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    1. Basics

    About Ceylon

    Ceylon is a n ew pro gramm ing language, designed to execute on the Java VirtualMachine, currently under development by my team here at Red Hat. We're f ansof Java and of the Java ecosystem, of it s practical orientatio n, of its culture o fopenness, of its developer community, of its root s in the world of businesscomputing, and of its ongoing commitment to portability. However, werecognize that the language and class libraries, designed more than 15 yearsago, are no longer the best foundation for a range of today's businesscomputing problems.

    Ceylon's design goals include:

    to be easy to learn and u nderst and f or Java and C# develop ers,

    to elim inate some of Java's verbosit y, whil e retaining its readabilit y,

    to im pr ove upon Java's typesafety,

    to provide a declarative syntax for expressing hierarchical information likeuser interface definition, externalized data, and system configuration,th ereby elim inati ng Java's dependence upon XML,

    to support and encourage a more functional style of programming withimm utable objects and higher- order functions,

    to provide great support for meta- prog ramm ing, thus making it easier towrite frameworks, and

    to provide built- in modularity.

    Above all, Ceylon is designed to make it easy and fun to get things done inlarge teams.

    The Ceylon compiler is not yet finished, so you can't write code in Ceylon yet.

    However, we would like t o g et the communit y involved in development of thelanguage and SDK, so thi s serious of art icles is a sneak preview for int erestedfolks.

    Let's start from the beginning.

    Writing a simple program

    Here's a classic exampl e pr ogr am.

  • 7/31/2019 Ceylon Language

    6/103

    6 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    void hello() {

    writeLine("Hello, World!");

    }

    This method prints Hello, World! on t he console. A t oplevel method like thi s isjust like a C fun ction it belo ng s di rectly to the packag e that con tain s it, it 'snot a member of any specific type. You don't need a receiving object to invokea toplevel method. Instead, you can just call it like this:

    hello();

    Ceylon do esn't have Java- style static methods, but you can think of toplevelmethods as filling the same role. The problem with static methods is that they

    break the block structure of the language. Ceylon has a very strict blockstructur e a nested bl ock always has access to declarations in all containingbl ocks. Thi s isn't th e case with Java's static methods.

    This method is declared using the void keyword, which means that the m ethoddeclaration doesn't specify a return value. When the method is executed, it callsanother toplevel method named writeLine(). This method displays its parameteron the console.

    Along with the void keyword , t here's also a t ype named Void, which is the returntype of any void method, and also the root of the Ceylon type system.

    doc "The root type, supertype of

    both Object (definite values)

    and Nothing (the null value)."

    shared abstract class Void()

    of Object | Nothing {}

    It might seem strange that a void method has a return type. The justification forthis is that all methods in Ceylon are functions. (But notnecessarily purefunctions like hello(), a Ceylon function can have side-effects.)

    At a very abstract level, every method accepts arguments and returns a result.The type Void, loosely speaking, is a way of representing the notion of anunknown value of an unknown type. You can assign any value, including null,to Void, but then there's no way to get it back out again, or even discover whattype of value it was. So, in theory, a void method has a return value, we justhave no way of finding out anything about that value. This stuff probablydoesn't sound very useful right now, but it will turn out to be useful when wediscuss higher order functions and Ceylon's typesafe metamod el.

  • 7/31/2019 Ceylon Language

    7/103

    7 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    Adding inline documentation

    It's usually a good idea to add some kind of documentation to importantmethods like hello(). One way we could do this is by using a C- style comment,either l ike thi s:

    /* The classic Hello World program */

    void hello() {

    writeLine("Hello, World!");

    }

    Or like t his:

    //The classic Hello World programvoid hello() {

    writeLine("Hello, World!");

    }

    But it's much better to use the doc annotation for comm ents t hat describedeclarations.

    doc "The classic Hello World program"

    void hello() {

    writeLine("Hello, World!");

    }

    The doc annotation contains documentation that is included in the output of theCeylon documentation compiler. The documentation compiler will supportseveral other annotations, including by, for specifying the author of a programelement, see, for referring to related code elements, and throws, for alerting theuser to exception types thrown by an executable program element.

    doc "The classic Hello World program"

    by "Gavin"

    see (goodbye)

    throws (IOException)

    void hello() {

    writeLine("Hello, World!");

    }

    There's also a deprecated annotation for marking program elements that will beremoved in a future version of the modul e.

    Notice that when an annotation argument is a literal, it doesn't need to beenclosed in parentheses.

  • 7/31/2019 Ceylon Language

    8/103

    8 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    Note also that annotations like doc, by, see, and deprecated aren't keywords.They're just ordinary identifiers. The same is true for annotations which are partof the language definition: abstract, variable, shared, formal, actual, and friends.On the other hand, void is a keyword.

    Strings and string interpolation

    The Hello World program wildly popular as it is provides for a ratherlimit ed and monot onous user ex perience. A more t ypical program wouldproduce output that sometimes varies between different runs.

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

    doc "The Hello World program... version 1.1!"

    void hello() {

    writeLine("Hello, this is Ceylon " process.languageVersion

    " running on Java " process.javaVersion "!");

    }

    Here we can see two nice things about strings in Ceylon. The first is that we cansplit a string across multiple lines. That's especially useful when we're writingdocumentation in a doc annotation. The second is that we can interpolateexpressions inside a string literal. Technically, a string with expressions in itisn't really a literal anymore it's considered a string template.

    A string template must begin and end in a string literal. The following is notlegal synt ax :

    writeLine("Hello, this is Ceylon " process.languageVersion); //compile error!

    A quick fix is to terminate the template with an empty string literal:

    writeLine("Hello, this is Ceylon " process.languageVersion "");

    Note that this isn't the only way to concatenate strings in Ceylon. Indeed, it'sonly useful when you're interpolating variables or expressions into anotherwise- constant string. The + operator you're probably used to is analternative, and more flexible in many cases:

    writeLine("Hello, this is Ceylon " + process.languageVersion +

    " running on Java " + process.javaVersion + "!");

    However, don't make the mistake of thinking that these two approaches arealways equivalent just because they result in the same output in this case.

  • 7/31/2019 Ceylon Language

    9/103

    9 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    The + operator immediately evaluates its operand expressions and produces animmutable Stringobject. On the ot her hand, a string template is an expressionof type Gettable, which evaluates its interpolated expressions lazily. Ifyou print the same string template object twice, you might see different outputthe second tim e around! In fact, a string template is a kind of closure animportant concept we'll explore further in Part 2.

    Dealing with objects that aren't there

    An even more exciting program would receive input and p roduce output thatdepends upon the input it receives. Of course, this places somewhat moredemanding r equirements upon t he user, b ut the extra work does sometim espay off!

    Therefore, this improved version of the original Hello World program takes aname as input from the command line. We have to account for the case wherenothing was specified at the command li ne, which gives us an opport unity toexplore how null values are treated in Ceylon, which is quite different to whatyou're p rob ably used t o i n Java or C#.

    doc "Print a personalized greeting"

    void hello() {

    String? name = process.arguments.first;

    String greeting;

    if (exists name) {

    greeting = "Hello, " name "!";

    }

    else {

    greeting = "Hello, World!";

    }

    writeLine(greeting);

    }

    The process object has an attribute named arguments, which holds a Sequence of

    the program's command line arguments. The local name is initialized with thefirst of these arguments, if any. This local is declared to have type String?, toindicate that it may contain a null value. Then the if (exists ...) controlstructure i s used to initialize the value of the non- null local named greeting,interpolating the value of name into the message string whenever name is not null.Finally, the message is printed to the console.

    Unlik e Java, locals, parameters, and attri but es that may contain null values mu stbe explicitly declared as being of optionaltype. And unlike other languages withtypesafe null value handling, an optional type in Ceylon is not an algebraicdatatype thatwr aps th e defini te value. Instead, Ceylon uses an ad- hoc union

  • 7/31/2019 Ceylon Language

    10/103

    10 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    type. The syntax T|S represents the union type of T and S, a t ype which maycontain a value of type T or of type S. An opt ional type is any type ofform Nothing|X where X is the type of the definite value. Fortunately, Ceylon letsus abbreviate the uni on type Nothing|X to X?.

    doc "The type of null."

    shared abstract class Nothing()

    of nothing

    extends Void() {}

    The value null is the unique instance of t ype Nothing, but it's not an instanceof Object. So there's simply no way to assign null to a local that isn't of optionaltype. The compiler won't let you.

    doc "Represents a null reference."

    object nothing extends Nothing() {}

    doc "Hides the concrete type of nothing."

    shared Nothing null = nothing;

    Nor will the Ceylon compiler let you do anything dangerous with a value oftype T? that is, anything that could cause aNullPointerException in Java without first checking that the value is not null using if (exists ... ). Moreformally, the if (exists ... ) construct lets us extract a value of type X from avalue of type X?, t hereby allowing us to invoke the m embers of X upon the value.

    In fact, it's not even possible to use the equality operator == with an expressionof optional t ype. You can't write if (x==null)li ke you can in Java. This h elpsavoid the undesirable behavior of == in Java wher e x==y evaluatesto true if x and y both evaluate to null.

    It's possible to declare the local name inside the if (exists ... ) condition:

    String greeting;

    if (exists String name = process.arguments.first) {

    greeting = "Hello, " name "!";

    }

    else {

    greeting = "Hello, World!";

    }

    writeLine(greeting);

    This is the preferred style most of the time, since we can't actually use name foranything useful outside of the if (exists ... ) construct.

  • 7/31/2019 Ceylon Language

    11/103

    11 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    Operators for handling null values

    While w e're di scussing null values, I should tell you about an even easier way t odefine greeting, using the ? operator. It's just a little extra syntax sugar to savesome keystr okes.

    shared String greeting = "Hello, " + name?"World";

    The ? operator returns its first argument if the first argument is not null, or itssecond argument otherwise. Its a more convenient way to handle null values insimple cases. It can even be chained:

    shared String greeting = "Hello, " + nickName?name?"World";

    The related ?. operator lets us call operations on optional types, alwaysreturning an optional t ype:

    shared String shoutedGreeting = "HELLO, " + name?.uppercase?"WORLD";

    Defaulted parameters

    A method parameter may specify a default value.

    void hello(String name="World") {

    writeLine("Hello, " name "!");

    }

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

    hello(); //Hello, World!

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

    Defaulted parameters must be declared after all required parameters in the

    parameter list of a method.

    Ceylon also support s sequenced parameters (varargs), declared using thesyntax T.... We'll come back to them aft er we d iscuss sequences and for loops.

  • 7/31/2019 Ceylon Language

    12/103

    12 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    2. Classes and members

    Creating your own classes

    Ceylon is an object oriented language, so we usually write most of our codein classes. A class is a t ype th at packages:

    operations called methods,

    state held by attributes,

    logic to initialize the state when the obj ect is first created, and,

    sometimes, other nested types.

    Types (interfaces, classes, and type parameters) have names that begin withuppercase letters. Members (method s and att rib utes) and locals have namesthat begin wi th lowercase lett ers. This is t he rule you're used to fr om Java.Unlik e Java, th e Ceylon compil er enforces t hese rules. If you t ry t o writ e classhello or String Name, you'll get a compilation error.

    Our first version of the Hello class has a single attribute and a single method:

    doc "A personalized greeting"

    class Hello(String? name) {

    doc "The greeting"

    shared String greeting;

    if (exists name) {

    greeting = "Hello, " name "!";

    }

    else {

    greeting = "Hello, World!";

    }

    doc "Print the greeting"

    shared void say(OutputStream stream) {

    stream.writeLine(greeting);

    }

    }

    To understand t his code completely, we're going t o need to first exp loreCeylon's approach to program element accessibility the shared annotation

  • 7/31/2019 Ceylon Language

    13/103

    13 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    above, then meet the concept of an attribute, and finally discuss how objectinitialization works in Ceylon.

    Hiding implementation details

    In Java and C#, a class controls the accessibil ity of its members u sing visibil itymodif ier annotations, allowing the class to hide its internal implementationfrom other code. The visibility modifiers select between pre- defined, definitevisibility levels like public, protected, package private, and private. Ceylonprovides just one annotation for access control. The key difference is thatCeylon's shared annotation does not represent a single definite scope. Rather, itsmeaning is contextual, relative to the program element at which it appears.The shared annotation is in some cases more flexible, in certain cases less

    flexible, but almost always simpler and easier to use than the approach takenby Java and C#. And it 's a far b etter f it to a language lik e Ceylon with a regular,recursive block structure.

    Members of a class are hidden f rom code outside th e body of the class bydefault only members explicitly annotated sharedare visible to other topleveltypes or methods, other compilation units, other packages, or other modules.A shared member is visible to any code to which the class itself is visible.

    And, of course, a class itself may be hidden from other code. By default, atoplevel class is hidden from code outside the package in which the class is

    defined only toplevel classes explicitly annotated shared are visible to otherpackages or modules. A shared toplevel class is visible to any code to which thepackage containing the class is visible.

    Finally, a package may be hidden from packages in other modules. In fact,packages are hidden from code outside the module to which the packagebelongs by default only explicitly shared packages are visible to othermodules.

    It's not possible to create a shared t oplevel class with package- privatemembers. Members of a shared toplevel class must be either shared in whichcase they're visible outside the package containing the class, or un- shared inwhich case they're only visible to the class itself. Package- privatefunctionality must be defined in un- shared (package- pr ivate) t opl evel classes o rinterfaces. Likewise, a shared package can't contain a m odule- private top levelclass. Module- pri vate top level classes m ust belong to unshared (mo dule-pr ivate) p ackages.

    Ceylon doesn't have anyth ing li ke Java's protected. The purpose of visibility r ulesand access control is to limit dependencies between code that is developed bydifferent teams, maintained by different developers, or has different release

  • 7/31/2019 Ceylon Language

    14/103

    14 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    cycles. From a software engineering point of view, any code element exposed toa different package or module is a dependency that must be managed. And adependency is a dependency. It's not any less of a dependency if the code towhich the program element is exposed is in a subclass of the type whichcontains the program element!

    Abstracting state using attributes

    The attribute greeting is a simple attribute, t he closest th ing Ceylon has to a Javafield. Its value is specified immediately after it is declared. Usually we candeclare and specify the value of an attribute in a single line of code.

    shared String greeting = "Hello, " name "!";

    shared Natural months = years * 12;

    The Ceylon compiler forces us to specify a value of any simple attribute or localbefore m aking use of the simple attribu te or local in an expr ession. Ceylon willnever automatically ini tialize an attr ibute t o any kind of default value or let codeobserve the value of an uninitialized att ribut e. This code results in an error atcompile time:

    Natural count;

    shared void inc() {

    count++; //compile error

    }

    An att ribut e is a bit diff erent t o a Java field. It's an abstraction of the notion of avalue. Some attri but es are sim ple value hold ers lik e th e one we've ju st seen;others are mor e like a getter m ethod, or, sometimes, like a getter and settermethod pair. Like m ethods, attribut es are polymorphican attribut e definitionmay be refined (overridden) by a subclass.

    We could rewrite t he attribut e greeting as a getter:

    shared String greeting {

    if (exists name) {

    return "Hello, " name "!";

    }

    else {

    return "Hello, World!";

    }

    }

    Notice that t he syntax of a getter d eclaration looks a lot like a methoddeclaration with no parameter list.

  • 7/31/2019 Ceylon Language

    15/103

    15 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    Clients of a class never need to know whether the attribute they access holdsstate directly, or is a gett er that d erives its value from other attribut es of thesame object or other objects. In Ceylon, you don't need to go around declaringall your attributes private and wrapping them in getter and setter methods. Getout of that habit right now!

    Understanding object init ialization

    In Ceylon, classes don't have constructors. Instead:

    the parameters needed to instantiate the class the initializerparameters are declared directly after the name of the class, and

    code to initialize the new instance of the class the class ini ti alizer goesdirectly in the body of the class.

    Take a close look at the f ollowing code fragment:

    String greeting;

    if (exists name) {

    greeting = "Hello, " name "!";

    }

    else {

    greeting = "Hello, World!";

    }

    In Ceylon, this code could appear in the body of a class, where it would bedeclaring and specifying the value of an immutable attribute, or it could appearin the body of a method definit ion, where it would be declaring and specifyingthe value of an im mu table local variable. That's not the case in Java, whereinitialization of fields looks very dif ferent to initialization of local variables!Thus the syntax of Ceylon is more regular than Java. Regu lari ty makes alanguage easy to learn and easy to refactor .

    Now let's turn our attention to a different possible implementation of greeting:

    class Hello(String? name) {

    shared String greeting {

    if (exists name) {

    return "Hello, " name "!";

    }

    else {

    return "Hello, World!";

    }

    }

  • 7/31/2019 Ceylon Language

    16/103

    16 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    ...

    }

    You might be wondering why we're allowed to use the parameter name inside thebody of the getter of greeting. Doesn't the parameter go out of scope as soon asthe ini tializ er t erminates? Well, that's tr ue, but Ceylon i s a language with a verystrict block structure, and the scope of declarations is governed by that blockstructure. In this case, the scope of name is the whole body of the class, and t hedefinition of greeting sits inside that scope, so greeting is permitt ed toaccess name.

    We've just met our first example of closure. We say that method and attribute

    definitions receive a closure of values defined in the class body to which theybelong. That's just a fancy way of obfuscating the idea that greeting holds ontothe value of name, even after the initializer completes.

    In fact, one way to look at the whole notion of a class in Ceylon is to think of itas a function which returns a closure of its own local variables. This helpsexplain why the syntax of class declarations is so similar to the syntax ofmethod declarations (a class declaration looks a lot like a method declarationwhere the r eturn type and the name of the m ethod are the same).

    Instantiating classes and overloading their initializer

    parameters

    Oops, I got so excited about attributes and closure and null value handling thatI forgot to show you the code that uses Hello!

    doc "Print a personalized greeting"

    void hello() {

    Hello(process.args.first).say(process.output);

    }

    Our rewritten hello() method just creates a new instance of Hello, andinvokes say(). Ceylon doesn't need a new keyword to know when you'reinstantiating a class. No, we do n't know why Java needs i t. You'll have to askJames.

    I suppose you're worried that if Ceylon classes don't have constructors, thenthey also can't have multiple constructors. Does that mean we can't overloadthe initialization parameter list of a class?

    I guess now's as good a time as any to break some more bad news: Ceylondoesn't support method overloading either! But, actually, this isn't as bad as it

  • 7/31/2019 Ceylon Language

    17/103

    17 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    sounds. The sad trut h is t hat overloading i s the source of various prob lems inJava, especially when generics come i nt o play. And in Ceylon, we can emu latemost non- evil uses of constructor or method overloading using:

    defaulted parameters, to emulate the effect of overloading a method orclass by arity (the number of parameters),

    sequenced parameters, i.e. varargs, and

    union typesor enumerated type constraints, t o emulate the effect ofoverloading a method or class by parameter type.

    We're not going to get into all the details of these workarounds right now, buthere's a quick example of each of the three techniques:

    //defaulted parameter

    void print(String string = "\n") {

    writeLine(string);

    }

    //sequenced parameter

    void print(String... strings) {

    for (String string in strings) {

    writeLine(string);

    }

    }

    //union type

    void print(String|Named printable) {

    String string;

    switch (printable)

    case (is String) {

    string = printable;

    }

    case (is Named) {

    string = printable.name;

    }

    writeLine(string);

    }

    Don't wo rry if you don't completely understand t he thir d exampl e just yet. Justthink of it as a completely typesafe version of how you would writean overloaded op eration in a dynamic l anguage lik e Smallt alk, Python, or Ruby.(If you're really im patient, skip f orward to the discussion of generic typeconstraints.)

    To be completely hon est, th ere are som e circumstances where th is approachends up slight ly more awkward than Java- style overloading. But that's a small

  • 7/31/2019 Ceylon Language

    18/103

    18 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    price to pay for a language with clearer semantics, without nasty corner cases,that is ultimately more powerful.

    Let's overload Hello, and it s say() method, using defaulted parameters:

    doc "A command line greeting"

    class Hello(String? name = process.args.first) {

    ...

    doc "Print the greeting"

    shared void say(OutputStream stream = process.output) {

    stream.writeLine(greeting);

    }

    }

    Our hello() method is now look ing r eally simple:

    doc "Print a personalized greeting"

    void hello() {

    Hello().say();

    }

  • 7/31/2019 Ceylon Language

    19/103

  • 7/31/2019 Ceylon Language

    20/103

    20 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    errors. We can't inadvertently refine a member or the superclass, orinadvertently fail to refine it.

    Notice that Ceylon goes out of its way to r epudiate the idea of duck t ypingor structural typing. If it walks() l ike a Duck, then it should be a subtypeof Duck and must explicitlyrefine the definition of walk() in Duck. We don't believethat the name of a method or attribute alone is sufficient to identify itssemantics.

    Abstr act classes

    There's one problem with what we've just seen. A personalized greeting is notreally a kind of default greeting. This is a case for introducing an abstract

    superclass:

    doc "A greeting"

    abstract class Hello() {

    doc "The (abstract) greeting"

    shared formal String greeting;

    doc "Print the greeting"

    shared void say(OutputStream stream) {

    stream.writeLine(greeting);

    }

    }

    Ceylon requires us to annotate abstract classes abstract, j ust li ke Java. Thisannotation specifies that a class cannot be instantiated, and can define abstractmem bers. Like Java, Ceylon also requi res us to annotat e abstr act m embers t hatdon't specify an implementation. However, in this case, the required annotationis formal. The reason for having two different annotations, as we'll see later, isthat nested classes may be either abstract or formal, and abstract nested classes

    are slightly different to formal member classes a formal member class may beinstantiated; an abstract class may not be.

    Note that an attribute that is never initialized is always a formal attribute Ceylon doesn't initialize attributes to zero or nullunless you explicitly tell it to!

    One way to define an im plementation for an inherited abstract attrib ute is t osimply assign a value to it in the subclass.

    doc "A default greeting"

  • 7/31/2019 Ceylon Language

    21/103

    21 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    class DefaultHello() extends Hello() {

    greeting = "Hello, World!";

    }

    Of course, we can also define an implementation for an inherited abstractattribute by refining it.

    doc "A personalized greeting"

    class PersonalizedHello(String name)

    extends Hello() {

    doc "The personalized greeting"

    shared actual String greeting {

    return "Hello, " name "!";

    }

    }

    Note that there's no way to prevent a other code from extending a class inCeylon. Since only m embers ex plicit ly declared as suppor tin g r efin ement usingeither formal or default can be refined, a subtype can never break theimplementation of a supertype. Unless the supertype was explicitly designed tobe extended, a subtype can add members, but never change the behavior ofinherited members.

    Interf aces and m ix in inheritance

    From time to time we come across a case where a class needs to inheritfuncti onality f rom mor e than one supertype. Java's inherit ance mod el doesn'tsupport this, since an interface can never define a member with a concreteimplementation. Interfaces in Ceylon are a little more flexible:

    An int erface may define concrete methods, attri bute gett ers, and att ributesetters.

    It may not define simple attributes or initialization logic.

    Notice that pr ohibiting simple att ribut es and initialization logic m akesint erfaces compl etely stateless. An interface can't hold references to otherobjects.

    Let's take advantage of mixin inheritance to define a reusable Writer interfacefor Ceylon.

    shared interface Writer {

  • 7/31/2019 Ceylon Language

    22/103

    22 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    shared formal Formatter formatter;

    shared formal void write(String string);

    shared void writeLine(String string) {

    write(string);

    write(process.newLine);

    }

    shared void writeFormattedLine(String formatString, Object... args) {

    writeLine( formatter.format(formatString, args) );

    }

    }

    Note that we can't define a concrete value for the formatter attribute, since aninterface may not define a simple attri bute, and m ay not hold a reference toanother object.

    Note also that the call to writeLine() from writeFormattedLine() resolves to theinstance method of Writer, which hid es the t oplevel method of the same name.

    Now let's define a concrete implementation of this interface.

    shared class ConsoleWriter()

    satisfies Writer {

    formatter = StringFormatter();

    shared actual void write(String string) {

    writeLine(string);

    }

    }

    The satisfies keyword is used to specify that an interface extends anotherinterface or that a class implements an interface. Unlike an extends declaration,a satisfies declaration does not specify arguments, since interfaces do not haveparameters or initialization logic. Furthermore, t he satisfies declaration canspecify more than one interface.

    Ceylon's approach to int erfaces elim inates a comm on pattern in Java where aseparate abstract class defines a default implementation of some of themembers of an interface. In Ceylon, the default implementations can be

  • 7/31/2019 Ceylon Language

    23/103

    23 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    specified by the interface itself. Even better, it's possible to add a new memberto an interface without breaking exi sting impl ementations of the int erface.

    Ambiguities in m ixin inheritance

    It's illegal for a type to inherit two members with the same name, unless thetwo members both (directly or indirectly) refine a common member of acommon supertype, and the inheriting type itself also refines the m ember toeliminate any ambig uity. The following results in a compilation error:

    interface Party {

    shared formal String legalName;

    shared default String name {

    return legalName;

    }

    }

    interface User {

    shared formal String userId;

    shared default String name {

    return userId;

    }

    }

    class Customer(String name, String email)

    satisfies User & Party {

    legalName = name;

    userId = email;

    shared actual String name = name; //error: refines two different members

    }

    To fix this code, we'll factor out a formal declaration of the attribut e name to acommon supertype. The following is legal:

    interface Named {shared formal String name;

    }

    interface Party satisfies Named {

    shared formal String legalName;

    shared actual default String name {

    return legalName;

    }

    }

  • 7/31/2019 Ceylon Language

    24/103

    24 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    interface User satisfies Named {

    shared formal String userId;

    shared actual default String name {

    return userId;

    }

    }

    class Customer(String name, String email)

    satisfies User & Party {

    legalName = name;

    userId = email;

    shared actual String name = name;

    }

    Oh, of course, t he following is illegal:

    interface Named {

    shared formal String name;

    }

    interface Party satisfies Named {

    shared formal String legalName;

    shared actual String name {

    return legalName;

    }

    }

    interface User satisfies Named {

    shared formal String userId;

    shared actual String name {

    return userId;

    }

    }

    class Customer(String name, String email)

    satisfies User & Party { //error: inherits multiple definitions of name

    legalName = name;

    userId = email;

    }

    To fix this code, name must be declared default in both User and Party andexpli citly refined in Customer.

  • 7/31/2019 Ceylon Language

    25/103

    25 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    Introduction

    Sometimes, especially when we're working with code from modules we don'thave control over, we would l ike to mix an interface into a type that has alreadybeen defined in another m odule. For example, we might like t o i ntroduce theCeylon collections module type List into the language module type Sequence, sothat all Sequences support all operations of List. But the language moduleshouldn't have a dependency to the collections module, so we can't specifythat interface Sequence satisfies List in the declaration of Sequence in the languagemodule.

    Instead, we can introducethe type Sequence in the code which uses thecollectio ns and language m odules. The collectio ns m odul e already defines an

    interface called SequenceList for this purpose. Well, it doesn't yet, since we havenot yet either implemented introductions or written the collections module, butit will soon!

    doc "Decorator that introduces List to Sequence."

    see (List,Sequence)

    shared interface SequenceList

    adapts Sequence

    satisfies List {

    shared actual default List sortedElements() {

    //define the operation of List in

    //terms of operations on Sequence

    return asList(sortSequence(this));

    }

    ...

    }

    The adapts clause makes SequenceList a special kind of interface called

    an adapter (in the t erminology used by this book). According to the languagespec:

    The interface may not:

    declare or inherit a member t hat refines a member of anyadapted type, or

    declare or inherit a formal or non- default actual member unlessthe m ember i s inherit ed f rom an adapted t ype.

  • 7/31/2019 Ceylon Language

    26/103

    26 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    The purpose of an adapter is to add a new supertype, called an introduced type,to an existing type, called the adapted type. The adapter doesn't change theoriginal definition of the adapted t ype, and it doesn't aff ect t he internalworkings of an instance of the adapted t ype in any way. All it does is fill in thedefinit ions of the m issing operations. Here, the SequenceListinterface providesconcrete i mplementations of all methods of List that are not alreadyimplemented by Sequence.

    Now, to introduce List to Sequence in a certain compilation unit, all we need to dois import the adapter:

    import ceylon.collection { List, SequenceList }

    ...

    //define a Sequence

    Sequence names = { "Gavin", "Emmanuel", "Andrew", "Ales" };

    //call an operation of List on Sequence

    List sortedNames = names.sortedElements();

    Note that t he introdu ction is not visible outside the lexical scope ofthe import statement (the compil ation unit). But within the compilation unitcontaining the import statement, every instance of of the adapted

    type Sequence now has all the attributes and methods of the introduced type List,and is assignable to the introduced type.

    Again, according to the spec:

    If, in a certain compilation unit, mult iple intr oductions of a certain adapted t ypedeclare or inherit a m emb er that r efines a comm on m ember o f a comm onsupertype then either:

    there must be a unique member from the set of members,called th e most refined member, that refines all the oth er

    members, or the adapted t ype must declare or inherit a member that refines

    all the members.

    At runtime, an operation (method invocation, member class instantiation, orattribute evaluation) upon any type that is a subtype of all the adapted types isdispatched according to the f ollowing rule:

    If t he runtim e type of the instance of t he adapted type declaresor inherits a member defining the operation, the operation isdispatched to the runt ime t ype of t he instance.

  • 7/31/2019 Ceylon Language

    27/103

    27 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    Otherwise, the operation i s dispatched to the int roduction thathas the most- refined member defining the operation.

    Introduction compared to ext ension methods and implicit typeconversions

    Introduction is Ceylon's way of extending a type after it's been defined.It's interesting to compare introduction to the following features of otherlanguages:

    ext ension m ethods, and

    user- defined implicit type conversions.

    Introduction is r eally just a much m ore powerful cousin of ext ension methods.From our p oint of view, an ex tension m ethod introduces a member to a type,without actually introducing a new supertype. Indeed, a Ceylon adapter withno satisfiesclause is actu ally a package of extension method s!

    shared interface StringSequenceExtensions

    adapts Sequence {

    shared String concatenated {

    variable String concat = "";

    for (String s in this) {concat+=s;

    }

    return concat;

    }

    shared String join(String separator=", ") {

    ...

    }

    }

    On t he other hand, introductions are less powerful than implicit typeconversions. This is by design! In this case, less powerful means safer, moredisciplined. The power of impl icit type conversions comes partly fr om theirability to work around some of t he designed- in limit ations of the type system.But these limitations have a purpose! I'm especially thinking of the prohibitionsagainst:

    inherit ing the same generic t ype twice, wit h diff erent type argum ents (inmost languages), and

  • 7/31/2019 Ceylon Language

    28/103

    28 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    overloading (in Ceylon).

    Implicit type conversions are an end- run around these restrictions,reintrod ucing t he ambiguities that these restrictions exist to solve.

    Furthermore, it's ext remely diff icult t o imagine a language with impli cit t ypeconversions that preserve the f ollowing import ant properties of the typesystem:

    transitivity of the assignability relationship,

    covariance of generic types,

    the semantics of the identity == operator, and

    the ability t o infer generic t ype arguments of an invocation or instantiation.

    Finally, implicit type conversions work by having the compiler introduce hiddeninvocations of arbitrary user- written procedural code, code that couldpotentially have side- effects or make use of temporal state. Thus, theobservable behavior of the program can depend upon precisely where and howthe compiler introduces these magic calls.

    Introductions are a kind of elegant compromise: m ore powerful than plainextension methods, safer than implicit type conversions. We think the beauty ofthis model is a major advantage of Ceylon over similar languages.

    Type aliases

    It's often useful to provide a shorter or more semantic name to an exi sting classor interface type, especially if the class or interface is a parameterized type. Forthis, we use a type alias, for example:

    interface People = Set;

    A class alias must declare its for mal parameters:

    shared class People(Person... people) = ArrayList;

    Member classes and member class refinement

    You'r e pro bably u sed to th e idea of an inn er class in Java a class declaratio nnested inside another class or method. Since Ceylon is a language with arecursive block structure, the idea of a nested class is more than natural. But inCeylon, a non- abstract nested class is actually considered a member of thecontaining type. For example, BufferedReader defines the member class Buffer:

  • 7/31/2019 Ceylon Language

    29/103

    29 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    class BufferedReader(Reader reader)

    satisfies Reader {

    shared default class Buffer()

    satisfies List { ... }

    ...

    }

    The member class Buffer is annot ated shared, so we can instantiate it like t his:

    BufferedReader br = BufferedReader(reader);

    BufferedReader.Buffer b = br.Buffer();

    Note that a nested t ype name m ust be q ualified b y the containing t ype name

    when used outside of the containing type.

    The member class Buffer is also annotated default, so we can refine it in asubtype of BufferedReader:

    shared class BufferedFileReader(File file)

    extends BufferedReader(FileReader(file)) {

    shared actual class Buffer()

    extends super.Buffer() { ... }

    }

    That's right: Ceylon lets us override a member class defined by a supertype!

    Note that BufferedFileReader.Buffer is a subclass of BufferedReader.Buffer.

    Now t he instantiation br.Buffer() above is a polymorphic operation! It m ightreturn an instance of BufferedFileReader.Buffer or an instanceof BufferedReader.Buffer, depending upon whether br refers to aplainBufferedReader or a BufferedFileReader. This is more than a cute trick.Polymorphic instantiation lets us elimi nate t hefactory method pattern fr om ourcode.

    It's even possible to define a formal member class of an abstract class.A formal member class can declare formal members.

    abstract class BufferedReader(Reader reader)

    satisfies Reader {

    shared formal class Buffer() {

    shared formal Byte read();

    }

    ...

    }

  • 7/31/2019 Ceylon Language

    30/103

    30 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    In t his case, a concrete subclass of the abstract class must refinethe formal member class.

    shared class BufferedFileReader(File file)

    extends BufferedReader(FileReader(file)) {

    shared actual class Buffer()

    extends super.Buffer() {

    shared actual Byte read() {

    ...

    }

    }

    }

    Notice the dif ference between an abstract class and a formal member class.An abstract nested class may not be instantiated, and need not be refined byconcrete subclasses of the containing class. A formal member class may beinstantiated, and must be refined by every subclass of the containing class.

    It's an interesting exercise to compare Ceylon's member class refinement withthe f unctionalit y of Java dependency in jection fr amework s. Both mechanismsprovide a means of abstracting the instantiation operation of a type. You canthink of the subclass that refines a m ember type as fil ling the same role as adependency configuration in a dependency injection framework.

    Anonymous classes

    If a class has no parameters, it's often possible to use a shortcut declarationwhich defines a named instance of the class, without providing any actual namefor the class itself. This is usually most useful when we're extendingan abstract class or implementing an interface.

    doc "A default greeting"

    object defaultHello extends Hello() {

    greeting = "Hello, World!";

    }

    shared object consoleWriter satisfies Writer {

    formatter = StringFormatter();

    shared actual void write(String string) {

    writeLine(string);

    }

    }

  • 7/31/2019 Ceylon Language

    31/103

    31 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    The downside to an object declaration is that we can't write code that refers tothe concrete type of defaultHello or consoleWriter, only to the named instances.

    You might be tempted to think of object declarations as defining singletons, butthat's not quite right:

    A t oplevel object declaration doesdefine a singleton.

    An object declarati on nested inside a class defines an ob ject p er in stance ofthe containing class.

    An object declaration nested inside a method, getter, or setter results in annew object each time the method, getter, or setter is executed.

    Let's see how thi s can be useful :

    interface Subscription {

    shared formal void cancel();

    }

    shared Subscription register(Subscriber s) {

    subscribers.append(s);

    object subscription satisfies Subscription {

    shared actual void cancel() {

    subscribers.remove(s);

    }

    }

    return subscription;

    }

    Notice how this code example makes clever use of the fact that thenested object declaration receives a closure of the locals defined in thecontaining method declaration!

    A dif ferent way t o t hink about the dif ference between object and class is to thinkof a class as a parametrized object. (Of course, there's one big difference:a class declaration defines a named type that we can refer to in other parts ofthe program.) We'll see later that Ceylon also lets us think of a method as aparametrized attribute.

    An object declarati on can refine an att rib ute d eclared formal or default.

    shared abstract class App() {

    shared formal OutputStream stream;

    ...

    }

    class ConsoleApp() extends App() {

  • 7/31/2019 Ceylon Language

    32/103

    32 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    shared actual object stream

    satisfies OutputStream { ... }

    ...

    }

    However, an object may not itself be declared formal or default.

  • 7/31/2019 Ceylon Language

    33/103

    33 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    4. Sequences

    Some kind of array or list construct is a universal feature of all programminglanguages. The Ceylon language module defines support for sequence t ypes. Asequence type is usually written X[] for some element type X. But this is reallyjust an abb revi ation for the union type Empty|Sequence.

    The int erf ace Sequence represents a sequence with at l east one elem ent . Thetype Empty represents an empt y sequence with no elements. Som e operations o fthe type Sequence aren't defined by Empty, so you can't call them if all you haveis X[]. Therefore, we need the if (nonempty ... ) construct to gain access tothese op erations.

    void printBounds(String[] strings) {

    if (nonempty strings) {

    //strings is a Sequence

    writeLine(strings.first + ".." + strings.last);

    }

    else {

    writeLine("Empty");

    }

    }

    Note how this i s just a continuation of the pattern established for null valuehandling.

    Sequence syntax sugar

    There's lots mor e syntactic sugar f or sequences. We can use a bunch of famili arJava- li ke syntax:

    String[] operators = { "+", "-", "*", "/" };

    String? plus = operators[0];

    String[] multiplicative = operators[2..3];

    Oh, and the expression {} returns a value of type Empty.

    However, unl ik e Java, all t hese syntactic const ruct s are pure abbr eviati ons. Thecode above is exactly equivalent to the following de- sugared code:

    Empty|Sequence operators = Array("+", "-", "*", "/");

    Nothing|String plus = operators.value(0);

    Empty|Sequence multiplicative = operators.range(2,3);

  • 7/31/2019 Ceylon Language

    34/103

    34 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    A Range is also a subtype of Sequence. The following:

    Character[] uppercaseLetters = 'A'..'Z';

    Natural[] countDown = 10..0;

    Is just sugar for:

    Empty|Sequence uppercaseLetters = Range('A','Z');

    Empty|Sequence countDown = Range(10,0);

    In fact, this is just a sneak preview of the fact that almost all operators inCeylon are just sugar for method calls upon a type. We'll come back to thislater, when we talk about operator polymorphism.

    Iterating sequences

    The Sequence interface extends Iterable, so we can iterate a Sequence usinga for loop:

    for (String op in operators) {

    writeLine(op);

    }

    Ceylon doesn't need C- style for loops. Instead, combine for with the range

    operator ...

    variable Natural fac:=1;

    for (Natural n in 1..100) {

    fac*=n;

    writeLine("Factorial " n "! = " fac "");

    }

    If, for any reason, we need to use the index of each element of a sequence wecan use a special variation of the for loop that is designed for iteratinginstances of Entries:

    for (Natural i -> String op in entries(operators)) {

    writeLine($i + ": " + op);

    }

    The entries() function returns an instance of Entries containingthe indexed elements of the sequence.

    Sequence and its supertypes

  • 7/31/2019 Ceylon Language

    35/103

    35 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    It's probably a good time to see some more advanced Ceylon code. What betterplace to find some than i n t he language module it self?

    Here's how the language module defines the type Sequence:

    shared interface Sequence

    satisfies Correspondence &

    Iterable & Sized {

    doc "The index of the last element of the sequence."

    shared formal Natural lastIndex;

    doc "The first element of the sequence."

    shared actual formal Element first;

    doc "The rest of the sequence, without the first

    element."

    shared formal Element[] rest;

    shared actual Boolean empty {

    return false;

    }

    shared actual default Natural size {

    return lastIndex+1;

    }

    doc "The last element of the sequence."

    shared default Element last {

    if (exists Element x = value(lastIndex)) {

    return x;

    }

    else {

    //actually never occurs if

    //the subtype is well-behaved

    return first;

    }

    }

    shared actual default Iterator iterator() {

    class SequenceIterator(Natural from)

    satisfies Iterator {

    shared actual Element? head {

    return value(from);

  • 7/31/2019 Ceylon Language

    36/103

    36 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    }

    shared actual Iterator tail {

    return SequenceIterator(from+1);

    }

    }

    return SequenceIterator(0);

    }

    }

    The most interesting operations are inheritedfrom Correspondence, Iterable and Sized:

    shared interface Correspondencegiven Key satisfies Equality {

    doc "Return the value defined for the

    given key."

    shared formal Value? value(Key key);

    }

    shared interface Iterable

    satisfies Container {

    doc "An iterator of values belonging

    to the container."

    shared formal Iterator iterator();

    shared actual default Boolean empty {

    return !(first exists);

    }

    doc "The first object."

    shared default Element? first {

    return iterator().head;}

    }

    shared interface Sized

    satisfies Container {

    doc "The number of values or entries

    belonging to the container."

    shared formal Natural size;

  • 7/31/2019 Ceylon Language

    37/103

    37 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    shared actual default Boolean empty {

    return size==0;

    }

    }

    shared interface Container {

    shared formal Boolean empty;

    }

    Empty sequences and the Bottom type

    Now let's see the d efinit ion of Empty:

    object emptyIterator satisfies Iterator {

    shared actual Nothing head {

    return null;

    }

    shared actual Iterator tail {

    return this;

    }

    }

    shared interface Empty

    satisfies Correspondence &

    Iterable & Sized {

    shared actual Natural size {

    return 0;

    }

    shared actual Boolean empty {return true;

    }

    shared actual Iterator iterator() {

    return emptyIterator;

    }

    shared actual Nothing value(Natural key) {

    return null;

    }

    shared actual Nothing first {

  • 7/31/2019 Ceylon Language

    38/103

    38 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    return null;

    }

    }

    The special type Bottom represents:

    the empty set, or equivalently

    the intersection of all types.

    Since the empty set is a subset of all other sets, Bottom is assignable to all othertypes. Why is this useful here?Well,Correspondence and Iterable are both covariant i n t he

    type parameter Element. So Empty is assignableto Correspondence and Iterable for any type T. That'swhy Empty doesn't need a type parameter. The following code is well- typed:

    void printAll(String[] strings) {

    variable Iterator i := strings.iterator();

    while (exists String s = i.head) {

    writeLine(s);

    i := i.tail;

    }

    }

    Since bot h Empty and Sequence are subtypes of Iterable, the uniontype String[] is also a subtype of Iterable.

    Another cool thing to notice here is the return type ofthe first and value() operations of Empty. You might have been expecting tosee Bottom? here, since they override supertype members of type T?. But as wesaw in Part 1, Bottom? is just an abbreviation for Nothing|Bottom. And Bottom is theempt y set, so the union Bottom|T of Bottom with any other type T is just Titself.

    The Ceylon com piler is able to do all thi s reasoning auto matically. So when itsees an Iterable, it knows that the operation first is of type Nothing, i.e. itis the value null.

    Cool, huh?

    Sequence g ot chas for Java developers

    Superf icially, a sequence type lo oks a l ot lik e a Java arr ay, b ut reall y it 's very,very dif ferent! First, of course, a sequence typeSequence is an immutable

  • 7/31/2019 Ceylon Language

    39/103

    39 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    interface, it's not a mutable concrete type like an array. We can't set the value ofan element:

    String[] operators = .... ;

    operators[0] := "**"; //compile error

    Furthermore, the index operation operators[i] returns an optional t ype String?,which results in quite different code idioms. To begin with, we don't iteratesequences by index lik e in C or Java. The fo llowin g code does not compil e:

    for (Natural i in 0..operators.size-1) {

    String op = operators[i]; //compile error

    ...

    }

    Here, operators[i] is a String?, which is not directly assignable to String.

    Instead, if we need access to the index, we use the special form of for shownabove.

    for (Natural i -> String op in entries(operators)) {

    ...

    }

    Likewise, we don't usually do an upfront check of an index against thesequence length:

    if (i>operators.size-1) {

    throw IndexOutOfBoundException();

    }

    else {

    return operators[i]; //compile error

    }

    Instead, we do the check after accessing the sequence element:

    if (exists String op = operators[i]) {

    return op;

    }

    else {

    throw IndexOutOfBoundException();

    }

    We especially don't ever need to write the following:

  • 7/31/2019 Ceylon Language

    40/103

    40 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    if (i>operators.size-1) {

    return "";

    }

    else {

    return operators[i]; //compile error

    }

    This is much cleaner:

    return operators[i] ? "";

    All t his m ay take a litt le getting used to. But what's nice is that all the exactsame idiom s also apply to ot her kinds of Correspondence,

    including Entries and Maps.

  • 7/31/2019 Ceylon Language

    41/103

    41 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    5. Unions, algebraic types, and type inference

    Narrowing th e type of an object reference

    In any language with subtyping there is the hopefully occasional need toperform narrowing conversions. In most statically- typed languages, this is atwo- part p rocess. For examp le, in Java, we fir st t est t he type of the ob ject usingthe instanceofoperator, and t hen att empt to downcast it using a C- styletypecast. This is quite curious, since there are virtually no good usesfor instanceof that don't involve an immediate cast to the tested type, andtypecasts with out type t ests are dangerou sly non- typesafe.

    As you can imagine, Ceylon, with its emphasis upon static typing, does thingsdif ferently. Ceylon doesn't have C- style t ypecasts. Instead, we m ust test andnarrow the type of an object reference in one step, using the special if (is ...)construct. This construct is very, very similar to if (exists ... ) and if (nonempty... ), which we met earlier.

    Object obj = ... ;

    if (is Hello obj)

    {

    obj.say();

    }

    The switch statement can be used in a similar way:

    Object obj = ... ;

    switch(obj)

    case (is Hello) {

    obj.say();

    }

    case (is Person) {

    stream.writeLine(obj.firstName);

    }

    else {stream.writeLine("Some miscellaneous thing");

    }

    These constructs protect us from inadvertantly writing code that would causea ClassCastException in Java, ju st l ik e if (exists ... ) protects us from writingcode that would cause a NullPointerException.

    More about union types

  • 7/31/2019 Ceylon Language

    42/103

  • 7/31/2019 Ceylon Language

    43/103

    43 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    ...

    }

    (This makes Hello into Ceylon's version of what the functional pr ogrammingcommunity calls an algebraic data type.)

    Now the compiler won't let us declare additional subclasses of Hello, and so theunion type DefaultHello|PersonalizedHellois exactly the same type as Hello.Therefore, we can write switch statements without an else clause:

    Hello hello = ... ;

    switch (hello)

    case (is DefaultHello) {

    writeLine("What's your name?");

    }

    case (is PersonalizedHello) {

    writeLine("Nice to hear from you again!");

    }

    Now, it's usually considered bad practice to write long switch statements thathandle all subtypes of a type. It makes the code non- extensible. Adding a newsubclass to Hello means breaking all the switch statements that exhaust itssubtypes. In object- oriented code, we usually try to refactor constructs like thisto use an abstract method of the superclass that is overridden as appropriate

    by subclasses.

    However, there are a class of problems where this kind of refactoring isn'tappropriate. In most object- oriented languages, these problems are usuallysolved using the visitor pattern.

    Visitors

    Let's consider the following tree visitor implementation:

    abstract class Node() {

    shared formal void accept(Visitor v);

    }

    class Leaf(Object val) extends Node() {

    shared Object value = val;

    shared actual void accept(Visitor v) {

    v.visitLeaf(this);

    }

    }

    class Branch(Node left, Node right) extends Node() {

    shared Node leftChild = left;

  • 7/31/2019 Ceylon Language

    44/103

    44 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    shared Node rightChild = right;

    shared actual void accept(Visitor v) {

    v.visitBranch(this);

    }

    }

    interface Visitor {

    shared formal void visitLeaf(Leaf l);

    shared formal void visitBranch(Branch b);

    }

    We can create a method which print s out the t ree by imp lementingthe Visitor interface:

    void print(Node node) {object printVisitor satisfies Visitor {

    shared actual void visitLeaf(Leaf l) {

    writeLine("Found a leaf: " l.value "!");

    }

    shared actual void visitBranch(Branch b) {

    b.leftChild.accept(this);

    b.rightChild.accept(this);

    }

    }

    node.accept(printVisitor);

    }

    Notice that the code of printVisitor looks just like a switch statement. It mustexplicitly enumerate all subtypes of Node. Itbreaks if we add a new subtypeof Node to the Visitor interface. This is correct, and is the desired behavior.By break, I mean that the compiler lets us know that we have to update ourcode to handle the new subtype.

    In Ceylon, we can achieve the sam e effect, wi th less verbosit y, by enumeratin gthe subtypes of Node in its definition, and using a switch:

    abstract class Node() of Leaf | Branch {}

    class Leaf(Object val) extends Node() {

    shared Object value = val;

    }

    class Branch(Node left, Node right) extends Node() {

    shared Node leftChild = left;

    shared Node rightChild = right;

    }

  • 7/31/2019 Ceylon Language

    45/103

    45 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    Our print() method is now much simpler, but still has the desired behaviorof breaking when a new subtype of Node is added.

    void print(Node node) {

    switch (node)

    case (is Leaf) {

    writeLine("Found a leaf: " node.value "!");

    }

    case (is Branch) {

    print(node.leftChild);

    print(node.rightChild);

    }

    }

    Typesafe enumeration s

    Ceylon doesn't have anyth ing exactly l ik e Java's enum declaration. But we canemulate the effect using t he of clause.

    shared class Suit(String name)

    of hearts | diamonds | clubs | spades

    extends Case(name) {}

    shared object hearts extends Suit("hearts") {}

    shared object diamonds extends Suit("diamonds") {}

    shared object clubs extends Suit("clubs") {}

    shared object spades extends Suit("spades") {}

    We're allowed to use the names of object declarations in the of clause if theyextend the language module class Case.

    Now we can exhaust all cases of Suit in a switch:

    void print(Suit suit) {

    switch (suit)

    case (hearts) { writeLine("Heartzes"); }

    case (diamonds) { writeLine("Diamondzes"); }

    case (clubs) { writeLine("Clidubs"); }

    case (spades) { writeLine("Spidades"); }

    }

    (Note that these cases are ordinary value cases, not case (is...) type cases.)

    Yes, t his i s a bi t mor e verb ose th an a Java enum, but it's also slightly moreflexible.

  • 7/31/2019 Ceylon Language

    46/103

    46 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    For a more practical example, let's see the definition of Boolean from thelanguage module:

    shared abstract class Boolean(String name)

    of true | false

    extends Case(name) {}

    shared object false extends Boolean("false") {}

    shared object true extends Boolean("true") {}

    And here's how Comparable is defined. First, the typesafe enumeration Comparison:

    doc "The result of a comparison between two

    Comparable objects."

    shared abstract class Comparison(String name)

    of larger | smaller | equal

    extends Case(name) {}

    doc "The receiving object is exactly equal

    to the given object."

    shared object equal extends Comparison("equal") {}

    doc "The receiving object is smaller than

    the given object."

    shared object smaller extends Comparison("smaller") {}

    doc "The receiving object is larger than

    the given object."

    shared object larger extends Comparison("larger") {}

    Now, the Comparable interface itself:

    shared interface Comparable

    satisfies Equality

    given Other satisfies Comparable {

    doc "The operator."

    shared formal Comparison compare(Other other);

    doc "The > operator."

    shared Boolean largerThan(Other other) {

    return compare(other)==larger;

    }

    doc "The < operator."

    shared Boolean smallerThan(Other other) {

    return compare(other)==smaller;

    }

  • 7/31/2019 Ceylon Language

    47/103

    47 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    doc "The >= operator."

    shared Boolean asLargeAs(Other other) {

    return compare(other)!=smaller;

    }

    doc "The

  • 7/31/2019 Ceylon Language

    48/103

    48 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    The inferred type of a method declared local is just the type of the returnedexpression.

    Type inference for sequence enumeration expressions

    What about sequence enum erati on expressions lik e th is:

    local sequence = { DefaultHello(), "Hello", 12.0 };

    What type is inferred for sequence? You m ight answer: Sequence where X is thecommon superclass or super- interface of all the element types. But that can'tbe right, since there might be more t han one comm on supertype.

    The answer is that the inferred type isSequence

    whereX

    is the union of all theelement expression types. In this case, the typeis Sequence. Now, this wor ks out nicely,because Sequence is covariant in T. So t he foll owing code is well typed:

    local sequence = { DefaultHello(), "Hello", 12.0 }; //type

    Sequence

    Object[] objects = sequence; //type Empty|Sequence

    As is the fol lowing code:

    local nums = { 12.0, 1, -3 }; //type Sequence

    Number[] numbers = nums; //type Empty|Sequence

    What about sequences that contain null? Well, d o you remember t he typeof null from Part 1 was Nothing?

    local sequence = { null, "Hello", "World" }; //type Sequence

    String?[] strings = sequence; //type Empty|Sequence

    String? s = sequence[0]; //type Nothing|Nothing|String which is just Nothing|String

    It's interesting just how useful union types tur n out to be. Even if you only very

    rarely exp licitly writ e code with any explicit union type declaration (and that'sprobably a good idea), they are still there, under the covers, helping thecompiler solve some hairy, otherwise- ambiguous, typing problems.

  • 7/31/2019 Ceylon Language

    49/103

    49 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    6. Generics

    Defini ng generic types

    We've seen plenty of parameterized types in this series of articles, but now let'sexplo re a f ew mor e details.

    Progr amming with generic t ypes is one of t he most dif fi cult part s of Java. That'sstill tr ue, to some ext ent, in Ceylon. But because the Ceylon language and SDKwere designed for generics from the ground up, Ceylon is able to alleviate themost painful aspects of Java's bo lted- on- later mod el.

    Just li ke in Java, only t ypes and m ethod s may declare type paramet ers. Also j ustlik e in Java, type p arameters are l isted b efore or dinary parameters, enclosed inangle brackets.

    shared interface Iterator { ... }

    class Array(Element... elements) satisfies Sequence { ... }

    shared Entries entries(Value... sequence) { ... }

    As you can see, the convention in Ceylon is to use meaningful names for typeparameters.

    Unlik e Java, we always do need to specify type arguments in a type declaration(there are no raw types in Ceylon). The following will not compile:

    Iterator it = ...; //error: missing type argument to parameter Element of Iterator

    We always have to specify a type argument in a type declaration:

    Iterator it = ...;

    On the other hand, we shouldn't need to exp licitly specify type arguments inmost method invocations or class instantiations. In principle it's very oftenpossible to infer t he type argum ents fr om the ordinary arguments. Thefol lowing code should be possible, ju st li ke it is in Java:

    Array strings = Array("Hello", "World");

    Entries entries = entries(strings);

    But we haven't yet figur ed out what exactly the t ype inference algorit hm will be(probably something involving union types!) and so the Ceylon compilercurrently requires t hat all type arguments be explicitly specified like t his:

  • 7/31/2019 Ceylon Language

    50/103

    50 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    Array strings = Array("Hello", "World");

    Entries entries = entries(strings);

    On the other hand, the following code does already compile:

    local strings = Array("Hello", "World");

    local entries = entries(strings);

    The root cause of very many pr oblems when wor ki ng wi th generic t ypes in Javais type erasure. Generic type parameters and arguments are discarded by thecompiler, and simply aren't available at runtime. So the following, perfectlysensible, code fr agm ents just would n't compile i n Java:

    if (is List list) { ... }if (is Element obj) { ... }

    (Where Element is a generic type parameter.)

    A major goal of Ceylon's type system is support for reified generics. Lik e Java,the Ceylon compiler performs erasure, discarding type parameters from theschema of the g eneric type. But unlik e Java, type argum ent s are supposed to bereified (available at runtime). Of course, generic type arguments won't bechecked f or typesafety by the underlying virtual m achine at runtim e, but typearguments are at least available at runtime to code that wants to make use of

    them explicitly. So the code fragments above are supposed to compile andfunction as expected. You will even be able to use reflection to discover thetype arguments of an instance of a generic type.

    The bad news is we haven't implemented this yet ;- )

    Finally, Ceylon elimin ates one o f the b its of Java generics t hat's really hard toget your head around: wild card types. Wild card types were Java's solut ion to theproblem of covariance in a generic type system. Let's first explore the idea ofcovariance, and then see how covariance in Ceylon works.

    Covariance and contravariance

    It all starts with the int uitive ex pectation that a collection of Geeks is a collectionof Persons. That's a reasonable intuition, but especially in non- functionallanguages, where collections can be mutable, it turns out to be incorrect.Consider the foll owing possible definit ion of Collection:

    shared interface Collection {

    shared formal Iterator iterator();

    shared formal void add(Element x);

  • 7/31/2019 Ceylon Language

    51/103

    51 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    }

    And let's suppose that Geek is a subtype of Person. Reasonable.

    The intuitive expectation is that t he following code should work:

    Collection geeks = ... ;

    Collection people = geeks; //compiler error

    for (Person person in people) { ... }

    This code is, f rankl y, perf ectl y reasonable t aken at f ace value. Yet in bot h Javaand Ceylon, this code results in a compiler error at the second line, wherethe Collection is assigned to a Collection. Why? Well, because if we

    let the assignment through , t he following code would also compile:

    Collection geeks = ... ;

    Collection people = geeks; //compiler error

    people.add( Person("Fonzie") );

    We can't let that code by Fonzie isn't a Geek!

    Using big words, we say that Collection is nonvariant in Element. Or, when we'renot trying to impr ess people with opaque terminology, we saythat Collection both produces via the iterator() method and consumes

    via the add() method the type Element.

    Here's where Java goes off and d ives down a rabbit hol e, successful ly usin gwildcards to squeeze a covariant or contravariant type out of a nonvariant type,but also succeeding in thoroughly confusing everybody. We're not going tofol low Java down the hole.

    Instead, we're going to refactor Collection into a pure producer interface and apure consumer interface:

    shared interface Producer {

    shared formal Iterator iterator();

    }

    shared interface Consumer {

    shared formal void add(Input x);

    }

    Notice that we've annotated the type parameters of these interfaces.

    The out annotation specifies that Producer is covariant in Output; that itprod uces i nstances of Output, b ut never consumes instances of Output.

  • 7/31/2019 Ceylon Language

    52/103

    52 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    The in annotation specifies that Consumer is contravariant in Input; that itconsumes instances of Input, but never produces instances of Input.

    The Ceylon compiler validates the schema of the type declaration to ensure thatthe variance annotations are satisfied. If you try to declare an add() methodon Producer, a compilation error results. If you try to declare an iterate() methodon Consumer, you get a similar compilation error.

    Now, let's see what that buys us:

    Since Producer is covariant in its type parameter Output, and since Geek is asubtype of Person, Ceylon lets you assign Producer to Producer.

    Furt hermore, since Consumer is contravariant in its type parameter Input, and

    since Geek is a subtype of Person, Ceylon lets youassign Consumer to Consumer.

    We can define our Collection interface as a mi xin of Producer with Consumer.

    shared interface Collection

    satisfies Producer & Consumer {}

    Notice that Collection remains nonvariant in Element. If we tried to add a varianceannotation t o Element in Collection, a compile time error would result.

    Now, the f ollowing code finally compiles:

    Collection geeks = ... ;

    Producer people = geeks;

    for (Person person in people) { ... }

    Which matches our original intuition.

    The following code also compiles:

    Collection people = ... ;Consumer geekConsumer = people;

    geekConsumer.add( Geek("James") );

    Which i s also int uit ively corr ect Jam es is most cert ainly a Person!

    There's two additional things t hat follow from the definition of covariance andcontravariance:

    Producer is a supertype of Producer for any type T, and

  • 7/31/2019 Ceylon Language

    53/103

    53 | P a g eSource: http://relation.to/tag/Introduction+to+Ceylon

    Consumer is a supertype of Consumer for any type T.

    These invariants can be very helpful if you need to abstract over all Producers orall Consumers. (Note, however, that if Producerdeclared upper bound typeconstraints on Output, then Producer would not be a legal type.)

    You're unlikely to spend much time writing your own collection classes, sincethe Ceylon SDK has a powerful collections framework built in. But you'll stillappreciate Ceylon's approach t o