log

taiar

Dart Programming Language - Introduction

This is the third of a post series where I’m going to talk about some new programming languages with a nice future ahead. During this series I’ll explore deeper the Ceylon, Dart, Elixir, Rust and Swift 2 languages.

The plan is to make a post a week until December 15 (or maybe a little more) and spend 2 weeks exploring each one of them. In the first week I’ll explore the general aspects of the language and make some comparisons with other very known and established languages. In the post of the second week I’ll go deeper inside each one of the languages and explore the individual advantages on use them.

All the posts

  1. Ceylon Introduction
  2. Ceylon Usage
  3. Dart Introduction
  4. Dart Usage
  5. Elixir Introduction
  6. Elixir Usage
  7. Rust Introduction
  8. Rust Usage

Preface

There are hundred of programming languages out there. Which one should we use? Which help do we have to choose well? How do they compare to each other? This document is an attempt to provide some answers to these questions. Naturally, it would not be possible to provide complete answers: as I mentioned, there are too many programming languages. Nevertheless, we chose five languages with a potential to grow in importance in the coming years. These programming languages are Elixir, Rust, Dart, Swift and Ceylon. During this project, we shall be talking about each one of them. These discussions will be in breath, not in depth. Their goal is to provide the reader with the minimum of information necessary to compare them, and who knows, to lure one or other interested person in learning them in a greater level of details. In any case, we hope to contribute a bit to the popularization of these programming languages, which - likely - will be paramount to the development of computer science in the next ten years.

Dart

How did it appear?

Dart is an open source script language focused in web applications and developed by Google1. It was announced at GOTO Conference 2011 (Aarhus, Denmark)2 and its first stable release, Dart 1.0, comes in November 20133.

It was designed by Lars Bak and Kasper Lund, both of them employed by Google. Lars has contributed to the Chrome Browser project developing the V8 JavaScript Engine4, the open source JavaScript engine that runs Google’s browser and gave birth to some other big projects like Node.js5.

Why was it designed and implemented?

In the words of Google6:

At Google we’ve written our share of web apps, and we’ve tried in many ways to make improvements to that development process, short of introducing a new language. Now we think it’s time to take that leap. We designed Dart to be easy to write development tools for, well-suited to modern app development, and capable of high-performance implementations.

But in pragmatic terms all this means that Google thinks that JavaScript is unproductive and his proposal to improve it was to design a better language for the browsers. Google is investing a lot of effort on both sides, JavaScript and Dart7 and believes that developers should have a choice when they build for the web. Adding a new option, such as Dart, does not imply replacing the JavaScript already existing option8.

Dart has its own Virtual Machine which enable the Dart programs to run on every systems. There is also a dar2js compiler which makes Dart code compile to JavaScript code and run on modern browsers. And there is the third option, the Dartium9 project that brings the Dart VM inside a Chromium Browser, so Dart can be used directly as a browser’s script language like JavaScript does at Chrome nowadays.

The Dart team isn’t focused in bring Dart to Google Chrome but in compiling Dart to JavaScript. They have decided not to integrate the Dart VM into Chrome but to generate a better JavaScript compilation10 11.

How can we use it, e.g., install and run?

Dart has it’s own Virtual Machine and has easy installations on all major systems. The current stable version of Dart is 1.12.2. For installation on a Mac you can use Homebrew:

1
2
brew tap dart-lang/dart
brew install dart

Also you can install the Dartium browser with:

1
2
brew tap dart-lang/dart
brew install dart --with-content-shell --with-dartium

For Linux there are Debian packages and these are the commands for installation on the Debian based systems:

1
2
3
4
5
sudo apt-get install apt-transport-https
sudo sh -c 'curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -'
sudo sh -c 'curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list'
sudo apt-get update
sudo apt-get install dart

There are other options to build and install on various Linux distros12.

There is also the versions of the SDK where you can download the portable package and link to your system’s path whatever you want: https://www.dartlang.org/downloads/archive/.

Now let’s check if the installation works. In any path (Dart doesn’t force directory structure) create the file called hello.dart with the following content:

1
2
3
main() {
  print("Hello Dart!");
}

Run with dart hello.dart and the “Hello Dart!” message must show up. Now test the JavaScript compilation by running, with the same hello.dart file, the command:

1
dart2js hello.dart

You might have the message Dart file (hello.dart) compiled to JavaScript: out.js. The contents of the file out.js is huge if compared to the initial Dart code. We will have more details of JavaScript compilation in the future. Now,if you have a JavaScript runtime in your system, like Node.js, you will have the same result of running the hello.dart file if you run:

1
node out.js

If you don’t have a JavaScript runtime in your system, you’ll test the JavaScript compilation by creating a test.html file in the same directory of the out.js file with the following content:

1
<script type="text/javascript" src="out.js"></script>

Then open the file in a modern browser (like Google Chrome or Mozilla Firefox) and open the browser console (by pressing the F12 key) and the message Hello Dart! is printed in the browser’s console.

Simple programs

I will demonstrate some features of the language by writing some simple programs and analysing some points right after it.

Dart Packages

Every Dart program is a library, even if it the program is not written using libraries definitions. Libraries not only provide APIs, but are a unit of privacy: identifiers that start with an underscore (_) are visible only inside the library (like private or protected members in Java).

Libraries can be distributed using packages. Dart has a powerful package manager that resolve package dependencies and package installation as we specify our project dependencies. Dart has also a huge repository of packages[https://pub.dartlang.org/] that delivers the packages listed as project’s dependencies.

Let’s implement a Dart example program that uses the package manager to install a library. This is the code of the program request.dart:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import 'dart:math';
import 'package:http/http.dart' as http;

readFromRemoteFile(url, sentence) {
  var rng = new Random();
  print(sentence);
  http.get(url).then((val){
    var texto = val.body;
    var frases = texto.split("\n");
    print(frases[rng.nextInt(frases.length)]);
  });
}

ramones() {
  readFromRemoteFile('http://aurelio.net/doc/ramones.txt',
    "Please wait, consulting the Ramones:");
}

main() {
  ramones();
}

The program above makes a http get request13 to a document with some phrases (one per line), choose a random line and print the phrase on it. If we try to run this program now, we’ll have some errors:

1
2
3
4
5
$ dart _request.dart
Unhandled exception:
Could not resolve a package location for base at file:///home/taiar/dev/monografia/mono1/dart/get_request/get_request.dart
#0      _handlePackagesReply (dart:_builtin:416)
#1      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:148)

As the error is telling us, the program could not resolve the package location. That happens because the command import 'package:http/http.dart' as http; is trying to use a package that is not from Dart’s default SDK and is not present in our environment. Dart SDK ships with a program called pub. With this tool we can define our program’s dependencies and install all the possible package’s dependencies these packages need to work. To configure the project’s dependencies, we’ll have to use the pub specifications. We define the program’s dependencies with a file called pubspec.yaml in the root of our project. For this example, the pubspec.yaml should look like this:

1
2
3
name: request
dependencies:
  http: any

It says that, for our project called request, we have a dependency with the package http, at any version (we are assuming that all http package versions have the functionalities we need to run our program). To install the dependencies, we have to run the command:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ pub get
Resolving dependencies... (5.5s)
+ charcode 1.1.0
+ collection 1.1.3
+ convert 1.0.0
+ crypto 0.9.1
+ http 0.11.3+2
+ http_parser 1.1.0
+ path 1.3.6
+ source_span 1.2.1
+ stack_trace 1.4.2
+ string_scanner 0.1.4
+ typed_data 1.0.0
Changed 11 dependencies!

As you can see, it downloads lots of other packages, all they are dependencies for the http package (and, or course, for our program). All done, if we try to run the program again, it might work correctly:

1
2
3
$ dart get_request.dart
Please wait, consulting the Ramones:
& I won't be back till monday

Asynchronous Programming

Dart is a single-threaded programming language. If any code blocks the thread of execution (for example, by waiting for a time-consuming operation like some heavy I/O operation or a network request) the program effectively freezes. Asynchronous operations let your program run without getting blocked. Dart uses Future objects to represent asynchronous operations.

Lets make a new version of our previous request.dart program. This new version will make 2 HTTP Get request: the usual Ramones quotes and the other one teach us how to say “Merry Christmas” in various languages of the world. This is the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import 'dart:math';
import 'package:http/http.dart' as http;

readFromRemoteFile(url, sentence) {
  var rng = new Random();
  print(sentence);
  http.get(url).then((val){
    var texto = val.body;
    var frases = texto.split("\n");
    print(frases[rng.nextInt(frases.length)]);
  });
}

ramones() {
  readFromRemoteFile("http://aurelio.net/doc/ramones.txt",
    "Please wait, consulting the Ramones:");
}

natal() {
  readFromRemoteFile("http://www.crossladies.com/feliz_natal.txt",
    "This is how we say 'Merry Christmas' in:");
}

main() {
  ramones();
  natal();
}

Running the program, we would have a result like:

1
2
3
4
Please wait, consulting the Ramones:
This is how we say 'Merry Christmas' in:
Havaiano  Mele Kalikimaka
Come along (surfin') baby wait and see (surfin' safari)

There is one problem with the program. The program has race conditions. When the ramones function is called, it prints a message on the screen and make the HTTP get request, setting a callback function that choose the line and prints the message when the response of the request returns. Before the response returns, the natal function is called, printing the message and waiting for another response from HTTP. Then the two responses are back (on diferent times) and printed too.

Dart has the concept of Future. A Future represents a means for getting a value sometime in the future 14 15 16. When a function that returns a Future is invoked, two things happen:

  1. The function queues up work to be done and returns an uncompleted Future object.
  2. Later, when a value is available, the Future object completes with that value (or with an error; we’ll discuss that later).

Lets rewrite the program solving the race conditions with futures to see how it works:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import 'dart:math';
import 'package:http/http.dart' as http;

readFromRemoteFile(url, sentence) async {
  var rng = new Random();
  print(sentence);
  var response = await http.get(url);
  var texto = response.body;
  var frases = texto.split("\n");
  print(frases[rng.nextInt(frases.length)]);
}

ramones() async {
  await readFromRemoteFile("http://aurelio.net/doc/ramones.txt",
    "Please wait, consulting the Ramones:");
}

natal() async {
  await readFromRemoteFile("http://www.crossladies.com/feliz_natal.txt",
    "This is how we say 'Merry Christmas' in:");
}

main() async {
  await ramones();
  natal();
}

We have all those asynchronous methods. We mark'em as asynchronous. We tell the program, which methods it must await the result for continue the execution. That’s all!

Quotes

References

Ceylon Programming Language - Usage

This is the second of a post series where I’m going to talk about some new programming languages with a nice future ahead. During this series I’ll explore deeper the Ceylon, Dart, Elixir, Rust and Swift 2 languages.

The plan is to make a post a week until December 15 (or maybe a little more) and spend 2 weeks exploring each one of them. In the first week I’ll explore the general aspects of the language and make some comparisons with other very known and established languages. In the post of the second week I’ll go deeper inside each one of the languages and explore the individual advantages on use them.

All the posts

  1. Ceylon Introduction
  2. Ceylon Usage
  3. Dart Introduction
  4. Dart Usage
  5. Elixir Introduction
  6. Elixir Usage
  7. Rust Introduction
  8. Rust Usage

Preface

There are hundred of programming languages out there. Which one should we use? Which help do we have to choose well? How do they compare to each other? This document is an attempt to provide some answers to these questions. Naturally, it would not be possible to provide complete answers: as I mentioned, there are too many programming languages. Nevertheless, we chose five languages with a potential to grow in importance in the coming years. These programming languages are Elixir, Rust, Dart, Swift and Ceylon. During this project, we shall be talking about each one of them. These discussions will be in breath, not in depth. Their goal is to provide the reader with the minimum of information necessary to compare them, and who knows, to lure one or other interested person in learning them in a greater level of details. In any case, we hope to contribute a bit to the popularization of these programming languages, which - likely - will be paramount to the development of computer science in the next ten years.

Ceylon example

To show some more interesting features of Ceylon, I wrote a version of the Producer-consumer problem. This is a classic example of a multi-process synchronization problem. It describes two processes, the producer and the consumer, who share a common, fixed-size storage (buffer) used as a queue. The producer’s job is to generate a piece of data, put it into the storage and start again. At the same time, the consumer is consuming the data (i.e., removing it from the storage) one piece at a time. The problem is to make sure that the producer won’t try to add data into the storage if it’s full and that the consumer won’t try to remove data from an empty storage. 1

The implementation relies strongly of the Java Thread libraries. The Producer and the Consumer objects runs on different threads, each instance of each object. The Storage class manage the additions of the producers and the remotions of the consumers on the buffer. For synchronicity I used the Java’s Semaphore class.

Let’s see the code and I’ll give the explanations:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import ceylon.collection { ArrayList }
import java.util.concurrent { Semaphore }
import java.lang { Thread, Math }

shared Integer getRandomInteger(Integer a, Integer b) {
  value range = b - a + 1;
  value fraction = (range * Math.random());
  return (fraction + a).integer;
}

class Producer(Storage storage, shared actual Integer id) extends Thread() {

  void produce() {
      if(Math.random() < 0.5) {
          storage.add(this);
      }
  }

  shared actual void run() {
      while(true) {
          this.produce();
          this.sleep(getRandomInteger(1, 4) * 1000);
      }
  }

}

class Consumer(Storage storage, shared actual Integer id) extends Thread() {

  void consume() {
      if(Math.random()  < 0.5) {
          storage.get(this);
      }
  }

  shared actual void run() {
      while(true) {
          this.consume();
          this.sleep(getRandomInteger(1, 4) * 1000);
      }
  }

}

class Storage(shared Integer storageSpaces) {

  value buffer = ArrayList<Integer>(storageSpaces);
  variable Integer lastEmpty = 0;
  value m = Semaphore(1);

  for(i in 0..(this.storageSpaces - 1)) {
      this.buffer.push(0);
  }

  shared void get(Producer|Consumer actor) {
      m.acquire();
      assert(actor is Consumer);
      print("[Consumer " + actor.id.string + "] Wants to consume!");
      if(this.lastEmpty == 0) {
          print("[Storage] I have nothing for you now. Look: ");
      } else {
          this.lastEmpty--;
          this.buffer.set(this.lastEmpty, 0);
          print("[Storage] Ok, I got a thing for you.");
      }
      m.release();
      this.printBuffer();
  }

  shared void add(Producer|Consumer actor) {
      m.acquire();
      assert(actor is Producer);
      print("[Producer " + actor.id.string + "] Produced something.");
      if(this.lastEmpty == this.storageSpaces) {
          print("[Storage] I'm full! Can't take it right now, look:");
      } else {
          this.buffer.set(this.lastEmpty, 1);
          this.lastEmpty++;
          print("[Storage] Tank you! I'll store it.");
      }
      m.release();
      this.printBuffer();
  }

  shared void printBuffer() {
      m.acquire();
      process.write("[ ");
      for (load in this.buffer) {
          process.write(load.string + " ");
      }
      print("]");
      m.release();
  }

}

shared void run() {
  value storage = Storage(15);

  value p1 = Producer(storage, 1);
  value p2 = Producer(storage, 2);

  value c1 = Consumer(storage, 1);
  value c2 = Consumer(storage, 2);

  p1.start();
  p2.start();

  c1.start();
  c2.start();
}

The first thing we see are the imports. We are already used to them, in the first article where I used already some Java interoperability and explained the concept of modules. Every of these things are used here.

Toplevel functions

After that, we can se a function called getRandomInteger. In Ceylon, this is a toplevel function. A toplevel function declaration, or a function declaration nested inside the body of a containing class or interface, may be annotated shared (in the last article, I talked about the shared annotation and the visibility issues). A toplevel shared function is visible wherever the package that contains it is visible.

Another interesting thing about toplevel functions in Ceylon is that they can be called by external programs on the system. On the example, I’ll modify the function a little so we can see what is going on:

1
2
3
4
5
6
7
shared Integer getRandomInteger(Integer a = 1, Integer b = 5) {
  value range = b - a + 1;
  value fraction = (range * Math.random());
  value gen = (fraction + a).integer;
  print(gen);
  return gen;
}

The toplevel function must have no parameters (or default value parameters) so you can call her externally. By placing our program inside a module called prodcons (see the module session on the first article), we can compile and run the program like:

1
2
3
ceylon compile

ceylon run --run prodcons::getRandomInteger prodcons

The random integer numbers between [1, 5[ will be generated by the program and printed on the screen.

Classes

We have then, the class Producer which is the very same class of the Consumer, except it calls different methods of the Storage class. The first interesting thing we can see is that Ceylon 1.1 has no constructor methods. Since the earliest versions of the language, it supports a streamlined syntax for class initialization where the parameters of a class are listed right after the class name, and initialization logic goes directly in the body of the class.2

We can instantiate the class Producer like this:

1
value prod = Producer(Storage(15), 1);

The ability to refer to parameters of the class directly from the members of the class has the intuit to cut down on verbosity. However, there are moments when we would really appreciate the ability to write a class with multiple initialization paths, something like constructors in Java. The constructors are being implemented on Ceylon and will be available in the next versions of the language.

The annotation shared on the parameter id says that this is like a Java’s public member of the class. storage is not annotated, so it is like a private one.

Look at the annotation actual that is used in the same id parameter and in the run method. It tells that, inside the inheritance tree of possible values (since the two classes extends the Thread Java class) that could overwrite the method or the variable, this is the very one that will do it. So, shared id is overwriting the parameter id (probably on the Thread Java class) and shared run is overwriting a run method (surely on the Thread Java class). In the case of Interfaces, the word to tell that a class implements (from Java) an interface is satisfies; so a class satisfies an interface. The annotation actual is used to tell what method is satisfying the Interface’s specification.

Collections, sequences and tuples

Ceylon SDK has a great library that implements every kind of collections, just like Java does. There are interfaces and classes to implement all sort of operations involving ArrayList, LinkedList, PriorityQueue, HashSet, HashMap, TreeSet, TreeMap etc.3 In our example, I used an ArrayList (wich is the implementation of a list using arrays) to store the production of the Producer.

In the example, I used a loop to initialize every cell of the buffer list with the value zero. In the for loop, I used a Sequence to generate the iterable value. Sequence is a type that in the first time could look very familiar to a Java array but in fact they are very different. First of all, the sequence is a immutable type and not a mutable concrete type like the array. We can’t set the value of an element like:

1
2
String[] operators = .... ;
operators[0] = "^"; //compile error

This following code, doesn’t compile too:

1
2
3
4
for (i in 0..operators.size-1) {
    String op = operators[i]; //compile error
    // ...
}

The index operation operators[i] returns an optional type String?, which cannot be assigned to the type String. Instead, if we need access to the index, we use the special form of for:

1
2
3
for (i -> op in operators.indexed) {
    // ...
}

Ceylon has the tuple type too. It might be a very common use for the most of those who already worked with a language that has tuples.

1
[Float,Float,String] point = [0.0, 0.0, "origin"];

Type system

Every value in a Ceylon program is an instance of a type that can be expressed within the Ceylon language as a class. The language does not define any primitive or compound types that cannot, in principle, be expressed within the language itself.

Each class declaration defines a type. However, not all types are classes. It is often advantageous to write generic code that abstracts the concrete class of a value. This technique is called polymorphism. Ceylon features two different kinds of polymorphism:

  • subtype polymorphism, where a subtype B inherits a supertype A, and
  • parametric polymorphism, where a type definition A is parameterized by a generic type parameter T.

Ceylon, like Java and many other object-oriented languages, features a single inheritance model for classes. A class may directly inherit at most one other class, and all classes eventually inherit, directly or indirectly, the class Anything defined in the module ceylon.language, which acts as the root of the class hierarchy.

In our example, we use a parameter of the methods add and get which is Producer|Consumer type. This type means that, whateaver a Producer or a Consumer parameter passed the this method, it’ll work. The methods doesn’t need this, I place'em there just for exemplification. In Ceylon, this is called Union types. For any types X and Y, the union, or disjunction, X|Y, of the types may be formed. A union type is a supertype of both of the given types X and Y, and an instance of either type is an instance of the union type.

Assertions and exceptions

The assert statement validates a given condition, throwing an AssertionException if the condition is not satisfied. A distinguishing characteristic of Ceylon is that exceptions aren’t used to represent programming errors. The Ceylon creators thinks that exceptions like NullPointerException, ClassCastException and IndexOutOfBoundsException should never occur in at runtime in a production system. They represent problems that must be fixed by the programmer editing code, tend to hide the “corner” condition they represent from someone reading the code and are much too low-level to carry any useful information about the real problem. Because of that, Ceylon tries to encode these “corner” conditions into the type system. The compiler won’t let you write:

1
print(process.arguments[1].uppercased);

This code isn’t well-typed because process.arguments[1] is of type String?, reflecting the fact that there might not be a second element in the list process.arguments. Instead you’re forced to at least take into account the possibility that there are less than two arguments:

1
2
3
4
5
6
if (exists arg = process.arguments[1]) {
    print(arg.uppercased);
}
else {
    throw Exception("missing second argument");
}

Obviusly, the code is a little bigger than the initial code we had but of course the problem is very much clear, semanthic and the readers of the code would understand the problem behind the size of the arguments in a much clearer way.

Concurrency

In our example, inside of the methods get and add of the Storage class is where we would have concurrency problems.1 To solve this potential problems, the class uses syncronization implemented with semaphores. I used the Semaphore class from Java “acquiring” and “releasing” the execution flow whateaver some of the Threads are updating the buffer or printing in the screen.

In Java is very common to use the synchronized method annotation to tell a Thread that this method have race conditions, and the JVM takes care of the concurrency. To use it with Ceylon, I had to especifically put the call to the syncronization methods because it doesn’t have the annotation nor any kind of compatibility with it.

Quotes

References

Ceylon Programming Language - Introduction

This is the first of a post series where I’m going to talk about some new programming languages with a nice future ahead. During this series I’ll explore deeper the Ceylon, Dart, Elixir, Rust and Swift 2 languages.

The plan is to make a post a week until December 15 (or maybe a little more) and spend 2 weeks exploring each one of them. In the first week I’ll explore the general aspects of the language and make some comparisons with other very known and established languages. In the post of the second week I’ll go deeper inside each one of the languages and explore the individual advantages on use them.

All the posts

  1. Ceylon Introduction
  2. Ceylon Usage
  3. Dart Introduction
  4. Dart Usage
  5. Elixir Introduction
  6. Elixir Usage
  7. Rust Introduction
  8. Rust Usage

Preface

There are hundred of programming languages out there. Which one should we use? Which help do we have to choose well? How do they compare to each other? This document is an attempt to provide some answers to these questions. Naturally, it would not be possible to provide complete answers: as I mentioned, there are too many programming languages. Nevertheless, we chose five languages with a potential to grow in importance in the coming years. These programming languages are Elixir, Rust, Dart, Swift and Ceylon. During this project, we shall be talking about each one of them. These discussions will be in breath, not in depth. Their goal is to provide the reader with the minimum of information necessary to compare them, and who knows, to lure one or other interested person in learning them in a greater level of details. In any case, we hope to contribute a bit to the popularization of these programming languages, which - likely - will be paramount to the development of computer science in the next ten years.

Ceylon

How did it appear?

Red Hat1 is the world’s leading provider of open source software solutions and it has initiated and sponsored2 the development of the Ceylon programming language. Ceylon is first and foremost an open source community project.

According to the language’s F.A.Q3, Ceylon was designed to be a modern Java with better specification, as we can see in the excerpt:

Well, we’ve been designing and building frameworks and libraries for Java for ten years, and we know its limitations intimately. And we’re frustrated. The most recent releases of Java go some distance to alleviating some problems, but even the newest language features strain to accommodate past mistakes and the requirement for full backward compatibility.

But much of our frustration is not even with the Java language itself. The extremely outdated class libraries that form the Java SE SDK are riddled with problems. Developing a great SDK is a top priority of the project.

Why was it designed and implemented?

Ceylon has a lot of interesting features but, we can start with this definition on the homepage4: “Ceylon is a language for writing large programs in teams”. The language is deeply influenced by Java and it was designed and implemented by people who were hugely involved with Java. People like Gavin King, the lead of the Ceylon project in Red Hat and also the creator of Hibernate5 (the most popular Object Relational Mapper for Java) and other projects in the Oracle’s platform.

Modularity is in the very core of the Ceylon language. When a Ceylon’s code is compiled, it produces module archives. In fact is very similar to Java’s modules. It generates a *.car file, with *.class files zipped on it. Just like Java’s *.jar. You’ll never be exposed to unpacked *.class files in Ceylon. So here we got 2 conclusions. The first one is that the compiler really forces the modularity and facilitates the distribution of the generated code. The second one is that the Ceylon compiled code runs on the Java Virtual Machine (JVM). This second fact is very important because by running on the JVM, Ceylon’s code is fully interoperable with Java, the Java SDK and its libraries. In fact, this interoperability is a major priority of the project.

This is an example of the use of the Java’s HashMap data structure on a Ceylon program:

1
2
3
4
5
6
7
import java.util { HashMap }

value javaHashMap = HashMap<String,Integer>();
javaHashMap.put("zero", 0);
javaHashMap.put("one", 1);
javaHashMap.put("two", 2);
print(javaHashMap.values());

Ceylon runs on the Javascript virtual machine too. In fact the Ceylon’s compiler can generate Javascript code if told to do so. It generates modular Javascript in the CommonJS modules format. We’ll see more on Javascript generation in the future.

1
2
3
4
5
6
7
8
9
10
11
12
13
dynamic {
    dynamic req = XMLHttpRequest();
    req.onreadystatechange = void () {
        if (req.readyState==4) {
            document.getElementById("greeting")
                    .innerHTML = req.status==200
                            then req.responseText
                            else "error";
        }
    };
    req.open("GET", "/sayHello", true);
    req.send();
}

Ceylon’s project always tells how important is the toolset for a complete and successful programing project so it ships with a really great Integrated Development Environment (IDE) built on a Eclipse plug-in. We’ll see more detailed information on the install and run section below.

How can we use it, e.g., install and run?

By running in the JVM, the Ceylon’s compiler got the advantage to run on every operating system which has a Java Virtual Machine implementation. It
runs both on Java 7 and Java 8 (prior versions are not supported). So before installing the Ceylon package, be sure to have the correct Java version installed. On this work, I’m using the 1.1 version of the language, released on 09 October 2014.

For installation on a Mac, you can use the Homebrew installer:

1
2
brew update
brew install ceylon

There are packages for both Debian and Fedora/Red Hat GNU/Linux flavors on the project’s download page: http://ceylon-lang.org/download/.

For a platform agnostic installation, download the zip archive (http://ceylon-lang.org/download/dist/1_1_0), unzip on your system’s prefered folder and add the /ceylon-1.1.0/bin folder to the path of your system. In a unix-like system you can do that by adding the line below on the ~/.bashrc file of you user’s directory:

1
export PATH="/path/to/ceylon-1.1.0/bin:$PATH"

Now let’s check if the installation works. By forcing the modularity, Ceylon implies some conventions on the compilation process. At first the code we’ll write must be on a “source” directory. So place the following code on a file called “./source/hello.ceylon”:

1
2
3
shared void hello() {
  print("Hello Ceylon!");
}

Outside the source’s folder, run the command:

1
ceylon compile source/hello.ceylon

Checkout the module folder created on the same level as the source folder. Check it’s content for the *.car file and some others. To run the compiled source, run the following command:

1
ceylon run --run hello default

Simple programs

I will demonstrate some features of the language by writing some simple programs and analysing some points right after it.

The treelike structure, simple classes and visibility

I’ll use this example to illustrate the treelike structure that Ceylon has. Ceylon’s named argument lists provide an elegant way for initializing objects and collections. The goal of this facility is to replace the use of XML for expressing hierarchical structures such as documents, user interfaces, configuration and serialized data.

I’ll use this notation to create a binary search tree and make a depth-first in-order traversal.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
shared class Node(val, left = null, right = null) {
  shared Integer val;
  shared Node? left;
  shared Node? right;
}

shared void caminhamento_central(Node b) {
  if(exists next = b.left) {
      caminhamento_central(next);
  }
  process.write(b.val.string + " ");
  if(exists next = b.right) {
      caminhamento_central(next);
  }
}

shared void run() {
  Node arvore = Node {
      val = 1;
      left = Node {
          val = 2;
          left = Node {
              val = 4;
              left = Node { val = 8; };
              right = Node { val = 9; };
          };
          right = Node {
              val = 5;
              left = Node { val = 10; };
              right = Node { val = 11; };
          };
      };
      right = Node {
          val = 3;
          left = Node {
              val = 6;
              left = Node { val = 12; };
              right = Node { val = 13; };
          };
          right = Node {
              val = 7;
              left = Node { val = 17; };
              right = Node { val = 15; };
          };
      };
  };

  caminhamento_central(arvore);
  print("");
}

The result of this program must be:

1
8 4 9 2 10 5 11 1 12 6 13 3 17 7 15

Look at the word shared on some points of the example. This shared annotation marks a declaration as being visible outside the scope in which it is defined, or a package as being visible outside the module to which it belongs6.

It’s all about visibility7. Classes, interfaces, functions, values, aliases, and type parameters have names. Occurrence of a name in code implies a hard dependency from the code in which the name occurs to the schema of the named declaration. We say that a class, interface, value, function, alias, or type parameter is visible to a certain program element if its name may occur in the code that belongs to that program element. The visibility of a declaration depends upon where it occurs, and upon whether it is annotated shared.

Random numbers and Java interoperability

Ceylon’s SDK is under constant development8 and there aren’t a random numbers implementation yet. But Ceylon can use the Java SDK, so I’ll use the Java random numbers interface to work on a Ceylon’s simple example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Import from Java SDK
import java.util { Random }

shared Integer getRandomInteger(Integer a, Integer b, Random r) {
  value range = b - a + 1;
  value fraction = (range * r.nextDouble());
  return (fraction + a).integer;
}

shared void run() {
    Random random = Random();
    for(number in 1..100) {
        print(getRandomInteger(1, 100, random));
    }
}

To use the Java SDK (and other libraries from outside the language’s SDK) you must use the module structure that is conventioned in the language. I’ll use this example to show it.

Save the code above on a file called random.ceylon inside of the following structure of directories: ./source/example/random/. This structure corresponds to the namespace of the module we are creating. It’s just like Java always did.

Inside this same folder, create the file module.ceylon. It is the file that will specify the dependencies our module have with external resources (like Java libraries) and formalize it’s namespace. The content of this file must be:

1
2
3
module example.random "1.0.0" {
    import java.base "8";
}

The java.base module in JDK has Java base packages such as java.lang, java.util, java.io, java.net, java.text, NIO and security9. All done, inside of the project’s root, run the command:

1
ceylon compile

The module will be compiled with the correct dependencies and the files will be generated in the correspondent directory of the module (in our example, it would be ./modules/example/random/1.0.0/). Then we can run the code with the command:

1
ceylon run example.random

The program will execute calling the method run (like the main method in Java) inside the package example.random.

Quotes

References

Testes De Aceitação No Codeigniter Com PHPUnit E Selenium

No meu primeiro artigo sobre testes no Codeigniter, abordei como faríamos para utilizar o PHPUnit para testes unitários no framework. O PHPUnit tem uma extensão que possibilita a integração com o Selenium RC, um servidor escrito em Java que consegue interagir com o Browser e executar testes como um usuário o faria. Meu objetivo aqui, como no primeiro artigo não é explorar o assunto de testes mas como integrar Codeigniter + PHPUnit + Selenium para fazer testes de aceitação. Para mais informações sobre os testes, veja as referências no final do artigo.

Como base para esta integração, vamos utilizar a aplicação que desenvolvemos no primeiro artigo, portanto, comece por lá! Considerando que você tem um sistema com as mesmas condições descritas lá, vamos inlcuir no projeto a extensão do PHPUnit para trabalhar com o Selenium. No arquivo composer.json, inclua a chave para baixar o componente:

{
  ...
  "require-dev": {
    ...
    "phpunit/phpunit": "4.1.*",
    "phpunit/phpunit-selenium": ">=1.2"
    ...
  }
  ...
}

e instale com o comando:

composer.phar update

Em seguida, baixe o Selenium RC Server. É um arquivo .jar único que poder ser obtido aqui. O Selenium webdriver usa como browser padrão o Firefox então você precisará tê-lo instalado. Você pode usar outro browser baixando outro webdriver mas nesse artigo utilizaremos o padrão. Para executar o servidor, na pasta onde seu arquivo se encontra:

java -jar selenium-server-standalone-2.*.*.jar

Certifique-se de que sua aplicação Codeigniter também esteja rodando corretamente em algum webserver.

DICA

À partir de alguma versão do PHP, ele vem com um webserver built-in que é bem prático para ambientes de desenvolvimento (evitando que você tenha que configurar um Apache ou Nginx apenas para desenvolver localmente). Vou usar essa funcionalidade aqui indo à pasta que contém a minha aplicação Codeingiter pela linha de comando e executando:

php -S localhost:8888

Ao acessar o browser, sua aplicação deve funcionar normalmente como em qualquer um dos servidores citados anteriormente. Até arquivos .htaccess do Apache são suportados por padrão o que pode faz essa funcionalidade ser compatível com a maioria dos projetos que temos atualmente. Na continuação desse artigo, executarei como descrito a minha aplicação (funciona normalmente se você utilizar outro método).

Voltando…

Vamos agora escrever um teste de exemplo que utilizará o Selenium webdriver. Neste teste iremos:

  1. Acessar a aplicação no atrvés do Firefox;
  2. Verificar se o título da página que iremos acessar é igual a “Welcome to CodeIgniter”, ou seja, a página inicial padrão do Codeigniter.

Eis o código do arquivo /tests/SeleniumTest.php:

<?php
class SeleniumTest extends PHPUnit_Extensions_Selenium2TestCase
{
    protected function setUp()
    {
        $this->setBrowser('firefox');
        $this->setBrowserUrl('http://localhost:8888/');
    }

    public function testTitle()
    {
        $this->url('http://localhost:8888/');
        $this->assertEquals('Welcome to CodeIgniter', $this->title());
    }

}

Após criar o arquivo, execute o PHPUnit como fizemos anteriormente:

./vendor/bin/phpunit

O resultado obtido deve ser parecido com:

taiar@guestxor:~/dev/ci$ ./vendor/bin/phpunit
PHPUnit 4.1.3 by Sebastian Bergmann.

Configuration read from /home/taiar/dev/ci/phpunit.xml.dist

..

Time: 6.33 seconds, Memory: 4.00Mb

OK (2 tests, 2 assertions)

Foram executados dois testes pois o primeiro era o teste unitário que criei no meu primeiro artigo. Como no artigo anterior, não abordarei aqui a teoria e todas as grandes vantagens por trás desses testes mas é recomendável estudo e aprofundamento no assunto. Como referência, deixo este link exemplificando diversas funções de verificação do PHPUnit Selenium e recomendo a leitura de todo o arquivo de exemplo afim de entender melhor as possibilidades que este servidor fornece.

Referências

Acceptance Tests on Codeigniter With PHPUnit and Selenium

In my first Codeigniter testing article, we take a look in how should we make unit testing with PHPUnit. PHPUnit has an extension that integrates with Selenium RC, a Java written server able to interact with the browser and run tests like an user would do. My point here, like in the first article is not to explore the testing issues but explain how to integrate Codeigniter + PHPUnit + Selenium so we can do acceptance tests. For more information about the tests, check the references in the end of the article.

As a base for this integration, we’ll use the first article’s application so you can start over there. Considering that you have a system with the same conditions described there, lets include in the project the PHPUnit extension to work with Selenium. In the composer.json file, insert the key to download the component:

{
  ...
  "require-dev": {
    ...
    "phpunit/phpunit": "4.1.*",
    "phpunit/phpunit-selenium": ">=1.2"
    ...
  }
  ...
}

and install with:

composer.phar update

Then, download the Selenium RC Server. It is a .jar file that can be obtained here. The Selenium Webdriver uses Firefox for the default browser so you must have it installed. You can use other browser but here we’ll use the default. To run the webdriver, in the file folder:

java -jar selenium-server-standalone-2.*.*.jar

Be sure that the Codeigniter application runs anywhere.

TIP

After some PHP version, it comes with a pragmatical and simple built-in webserver for development environments (avoiding to configure a Apache or Nginx just for local dev). I’ll use it here going on the Codeigniter main folder and inserting the command:

php -S localhost:8888

You can check in your browser that the application runs perfectly. Even .htaccess Apache files are supported what makes this functionality compatible with the most of the projects.

Returning…

Now we’ll write a sample test that’ll use Selenium Webdriver. In this test we’ll:

  1. Access the application using Firefox;
  2. Check if the title of the page is “Welcome to CodeIgniter”, that means, the default Codeigniter’s start page.

Here is the code of the /tests/SeleniumTest.php file:

<?php
class SeleniumTest extends PHPUnit_Extensions_Selenium2TestCase
{
    protected function setUp()
    {
        $this->setBrowser('firefox');
        $this->setBrowserUrl('http://localhost:8888/');
    }

    public function testTitle()
    {
        $this->url('http://localhost:8888/');
        $this->assertEquals('Welcome to CodeIgniter', $this->title());
    }

}

After the file is created, run PHPUnit as we did before:

./vendor/bin/phpunit

The result should be something like:

taiar@guestxor:~/dev/ci$ ./vendor/bin/phpunit
PHPUnit 4.1.3 by Sebastian Bergmann.

Configuration read from /home/taiar/dev/ci/phpunit.xml.dist

..

Time: 6.33 seconds, Memory: 4.00Mb

OK (2 tests, 2 assertions)

Two tests were executed because of the first one of the first article. Like in the first article I’ll not talk about the testing theory and its benefits but I would hardly recommend that you should do. As a reference, I’ll let this link with many samples of the PHPUnit Selenium functions and I recommend the read of the whole file for a better understanding of all the possibilities Selenium offers.

References