Recently, Kotlin has been gaining active popularity. And what if you try to choose more exotic languages and apply the same arguments to them? The article was written based on this , almost repeating all the arguments for Kotlin. The main task: to show that Ceylon can almost the same as Kotlin, with reference to Java. But apart from that, Ceylon has something else that will be described in the next article.
I want to talk about a new programming language called Ceylon and explain why you should use it in your next project. I used to write in Java (long and long, over 10 years, starting with Java 1.4 and ending with Java 8), and I liked Java. Then Scala made a big impression on me, as a result of which Java as a language began to love somewhat less. But fate brought me to the language of Ceylon, and in the last year and a half we write on Ceylon wherever possible. In real commercial projects, the truth is internal. And at the moment I can’t imagine a situation in which it would be better to choose Java, I don’t see Java as the language in which to start new projects.
Ceylon is developed in Red Hat, the author of the language is Gavin King, known for such a framework as Hibernate. It was created by people who understand Java flaws well, the main goal was to solve purely applied problems, to ensure the easiest readability of the code, to avoid any ambiguities and pitfalls, the foremost thing was the predictability and structural beauty of the language. Much attention was also paid to acceptable compile times. Currently, the language version is 1.3.2, I immediately became acquainted with the language when version 1.2.0 was released.
Although Ceylon is compiled into JavaScript, I will focus on its primary environment, the JVM.
So, there are several reasons why you should completely switch to Ceylon (the order coincides with the items of the same name in the corresponding Kotlin article):
0 # Java Compatibility
Like Kotlin, like Scala, Ceylon is 100% compatible with Java. You can literally continue to work on your old Java project, but already using Ceylon. All Java frameworks will also be available, and, whatever framework you write, Ceylon will be easily accepted by a stubborn Java lover. You can call code from Java without problems, Java code is also called without problems.
1 # Familiar syntax
One of the main features of Ceylon is the most convenient syntax for existing developers. If you take an existing Java developer, then with the understanding of Ceylon syntax, it will not have the slightest problem. Even languages like Scala and Kotlin will be less similar to Java. Below is a code showing a significant number of language constructions, similar to the Kotlin example:
class Foo(String a) { String b= "b"; // unmodifiable variable Integer i = 0; // variable means modifiable void hello() { value str = "Hello"; print("``str`` World"); } Integer sum(Integer x, Integer y) { return x + y; } Float maxOf(Float a, Float b) => if (a > b) then a else b }
Accordingly, you can continue to write without problems in Java style on Ceylon.
2 # Interpolation of lines
This is a smarter and more readable version of String.format () from Java, embedded in the language:
value x = 4; value y = 7; print("sum of ``x`` and ``y`` is ``x + y``") ; // sum of 4 and 7 is 11
IMHO syntax here will be more pleasant than in Kotlin, I don’t even want to compare it with Java.
3 # Type inference
Ceylon will infer your types if you think it will improve readability:
value a = "abc"; // type inferred to String value b = 4; // type inferred to Integer Float c = 0.7; // type declared explicitly List<String> d = ArrayList<String>(); // type declared explicitly
4 # Smart casts (Smart Casts)
The Ceylon compiler keeps track of your logic and, to the extent possible, performs type casting, i.e. you no longer need the instanceof checks after the explicit cast:
if (is String obj) { print(obj.uppercased) // obj is now known to be a String }
5 # Intuitive Equals
You can no longer explicitly call equals (), because the == operator now checks for structural equality:
value john1 = Person("John"); //we override equals in Person value john2 = Person("John"); print(john1 == john2); // true (structural equality) print(john1 === john2); // false (referential equality)
6 # Arguments by default
You no longer need to define several identical methods with different arguments:
void build(String title, Integer width = 800, Integer height = 600) { return Frame(title, width, height); }
7 # Named Arguments
In conjunction with the default arguments, named arguments eliminate the need to use Builders:
build("PacMan", 400, 300) // equivalent build {title = "PacMan"; width = 400; height = 300;} // equivalent build {title = "PacMan"; height = 300;} // equivalent with default width
8 # switch expression
The branch statement is replaced with a much more readable and flexible switch statement:
switch (obj) case(1) { print("x is 1"); } case(2) { print("x is 2"); } case(3 | 4) { print("x is 3 or 4"); } case(is String) { print ("x is String"); } case([Integer a, Float b, String c]) {print ("x is tuple with Integer ``a``, Float ``b`` and String ``c``");} else { print("x is out of range");}
switch can work as an expression, also the result of switch can be assigned to a variable:
Boolean|IllegalStateException res = switch(obj) case(null) false case(is String) true else IllegalStateException();
This is not a complete pattern matching, but for most cases the current functionality is enough.
Unlike Kotlin, Ceylon requires that all conditions be disjoint to the switch, that is, do not overlap, which is much more logical for the switch. If a range mapping is required or conditions may overlap, then the usual if should be used.
9 # Properties
You can add custom set & get behavior to public fields, i.e., stop stuffing code with crazy getters and setters.
class Frame() { variable Integer width = 800; variable Integer height = 600; Integer pixels => width * height; }
10 # Data Class
Unfortunately, this functionality is not yet available. I would very much like to have immutable classes in which the toString (), equals (), hashCode () and copy () are overridden by the automaton, but, unlike Java, they did not occupy 100 lines of code.
But the fact that this is not yet in the language does not mean that it is impossible to do. I will give an example of how the necessary functionality is implemented through libraries through the means of the language itself:
class Person(shared String name, shared String email, shared Integer age) extends DataObject() {} value john = Person("John", "john@gmail.com", 112); value johnAfterBirhstday = john.copy<Person>({`Person.age`->113;}); assertEquals(john, john.copy<Person>()); assertEquals(john.hash, john.copy<Person>().hash);
That is, at the library level, it turned out to redefine toString, leave the class immutable, we were able to create clones and changes to individual attributes. Unfortunately, it does not work as fast as it could if support was in the language. And there is no type checking at compile time = if we clone with redefinition in age and specify the string as the value, we get an error in runtime. The fact that there is no such functional yet is definitely bad. But the fact that we can write the necessary functionality independently at the library level is very good.
11 # Operator Overloading
A predefined set of statements that can be overloaded to improve readability:
class Vec(shared Float x, shared Float y) satisfies Summable<Vec> { shared actual Vec plus(Vec v) => Vec(x + vx, y + vy); } value v = Vec(2.0, 3.0) + Vec(4.0, 1.0);
12 # Destructuring Declarations
Some objects can be destructured, which is useful, for example, to iterate a map:
for ([key -> [val1, val2, val3]] in map) { print("Key: ``key``"); print("Value: ``val1``, ``val2``, ``val3``"); }
13 # Ranges
To improve readability:
for (i in 1..100) { ... } for (i in 0 : 100) { ... } for (i in (2..10).by(2)) { ... } for (i in 10..2) { ... } if (x in 1..10) { ... }
In contrast, Kotlin did without the downTo keyword.
14 # Extension Functions
They are not. It may appear that this possibility was considered in the early language specifications. But instead of the extension functions, in principle, top level functions work. If we, for example, want to add the sayHello method to the String class, then "world" .sayHello () does not look much better than sayHello ("world"). In the future they may appear.
In principle, the corresponding functions available for the class allow you to find the IDE itself, sometimes it works.
15 # Security Null
Java should be called an almost statically typed language. Inside it, a variable of type String does not necessarily refer to a String — it can refer to null. And although we are used to this, it reduces the security of checking for static typing, and as a result, Java developers are forced to live in constant fear of NPE.
In Ceylon, this problem is resolved by dividing into types that allow and not allow null. By default, types do not allow null, but you can convert them to allowable if you add?:
variable String a = "abc"; a = null; // compile error variable String? b = "xyz"; b = null; // no problem
Due to the functional union types String? it's just syntactic sugar for String | Null. Accordingly, you can write:
variable String|Null = "xyz"; = null; // no problem
Ceylon forces you to fight NPE when you refer to a type that allows null:
value x = b.length // compile error: b might be null
It may look cumbersome, but due to its several capabilities it is really useful. We still have smart type conversions where types that admit null are converted to not allowing:
if (!exists b) { return; } value x = b.length // no problem
You can also use the secure call?., It returns null instead of dropping NPE:
value x = b?.length; // type of x is nullable Int
You can chain safe calls to avoid nested if-non-null checks that we sometimes write in other languages. And if by default we need a non-null value, then we use the elvis operator else
value name = ship?.captain?.name else "unknown";
If all this does not suit you and NPE is absolutely necessary for you, then tell about it clearly:
value x = b?.length else NullPointerException() // same as below assert(!NullPointerException x);
16 # Improved lambda
This is a good lambda system - the perfect balance between readability and conciseness thanks to several sensible solutions. The syntax is simple:
value sum = (Integer x, Integer y) => x + y; // type: Integer(Integer, Integer) value res = sum(4,7) // res == 11
Accordingly, the syntax can be:
numbers.filter( (x) => x.isPrime() ); numbers.filter(isPrime)
This allows us to write concise functional code:
persons .filter ( (it) => it.age >= 18) .sort(byIncreasing(Person.name)) .map ( Person.email ) .each ( print );
The lambda system plus syntactic features of the language makes Ceylon a good tool for creating DSL. An example of a DSL similar to Anko in Ceylon syntax:
VerticalLayout { padding = dip(30); { editText { hint = "Name"; textSize = 24.0; }, editText { hint = "Password"; textSize = 24.0; }, button { "Login"; textSize = 45.0; } } };
17 # IDE support
By the way, it's pretty good. There is an eclipse plugin, there is an IDEA plugin. Yes, in terms of features and bugs, everything is somewhat worse than in Scala or Kotlin. But in principle, you can work and quite comfortably, the problems of IDE at the speed of development have virtually no effect.
So, if you take the strengths of Kotlin, Ceylon is inferior to Kotlin by the lack of DataObject functionality (which can be emulated independently by means of libraries). Otherwise, it provides not less features, but with a more pleasant syntax for reading.
Well, just like on Kotlin, on Ceylon you can write for Android.
After reading the above, you might get the impression - why do we need this? The same is in Kotlin, almost 1 in 1.
And the fact that in Ceylon there are things that are not present in either Kotlin or Scala, and due to these things the language itself is in many ways much better than other languages. For example, union types, intersection types, enumerated types, more powerful generics, modularity, herd, annotations and metamodel, tuples, for comprehensions. What really changes the approach to programming, allows you to write a much more reliable, understandable and universal code. But about it in the following part.
https://ceylon-lang.org/documentation/1.3/introduction/
https://ceylon-lang.org/documentation/1.3/faq/language-design/
https://dzone.com/articles/a-qa-with-gavin-king-on-ceylon
https://www.slant.co/versus/116/390/~scala_vs_ceylon
https://www.slant.co/versus/390/1543/~ceylon_vs_kotlin
https://dzone.com/articles/ceylon-enterprise-ready
http://tryge.com/2013/12/13/ceylon-and-kotlin/
Source: https://habr.com/ru/post/330412/
All Articles