
Top Ceylon language features I wish we had in Java - lukaseder
http://blog.jooq.org/2013/12/03/top-10-ceylon-language-features-i-wish-we-had-in-java/
======
quarterto

      7. Type aliases
      Is there any other programming language that ever thought of this awesome feature??
    

Um. To name a few: C has typedef; Go has type; Haskell has newtype.

~~~
Uchikoma
And Scala as another JVM language.

~~~
yareally
Kotlin, Ceylon's close JVM cousin, is going to eventually add them as well.

[http://blog.jetbrains.com/kotlin/2012/01/the-road-
ahead/](http://blog.jetbrains.com/kotlin/2012/01/the-road-ahead/)

~~~
dodyg
Kotlin has changed so much that you can't really rely on that 2012 road map.

~~~
yareally
One of their developers mentioned a few months ago that type aliases were
still an upcoming feature[1], though I do agree with your statement in
general.

[1] [http://blog.jetbrains.com/kotlin/2013/08/kotlin-m6-is-
here/#...](http://blog.jetbrains.com/kotlin/2013/08/kotlin-m6-is-
here/#comment-9023)

------
RivieraKid
Ceylon has a potentional to become the best statically typed language
available. I really love the elegance combined with the pragmatic focus on
readability, toolability and type-safety. Ceylon is so refreshing compared to
Scala. Unfortunately it didn't get a lot of attention on HN, I'm quite curious
what other people's impressions are.

~~~
pron
Ceylon is _very_ similar to Kotlin, but I much prefer Kotlin, mostly because
it so seamlessly interoperates with Java (more so than any other JVM language
I'm aware of). Also, Kotlin already has kickass IDE support.

~~~
RivieraKid
Agree that Kotlin has slightly better interoperability and IDE support (but
Ceylon is interoperable with Java too and has an Eclipse-based IDE).

But I like Ceylon more because:

* Union and intersection types.

* I find the type system cleaner and more elegant.

* It's an attempt to build a whole new platform with a new SDK. Kotlin is, in a way, just a syntax skin over the Java platform.

* Reified generics. Kotlin got rid of them.

* I personally find Ceylon's "String str" more readable than Kotlin's "str: String".

* Type-safe metaprogramming.

* Comprehensions (not 100% sure Kotlin doesn't have them).

* It's compilable to JS.

* Slightly more regular syntax, more readable generic declarations, better web documentation, currying, spread operator, etc.

~~~
pron
Kotlin also compiles to JS and has typesafe Groovy-style builders. I don't
like the union and intersection types, and think Kotlin being "a syntax skin
over the Java platform" is its main advantage.

Thing is, neither Kotlin nor Ceylon (nor Scala, IMO) add something
fundamentally necessary over what's available in Java (8). They mostly provide
productivity enhancements. For me, added productivity is really nice, but it
doesn't justify switching a language, unless it's a 10x productivity boost
(Clojure is different; it provides a whole new way of thinking and managing
state and data, which is very important for concurrency - this is big). So in
that case, I'd rather give Java a facelift than change to something else
altogether. Kotlin is just a Java facelift. It's trivial and transparent to
mix Kotlin and Java classes, even in the same package.

~~~
RivieraKid
Productivity and how fun is it to use a language are about the only metrics
that I care about. Even small productivity increase can be a reason to switch
language.

I don't understand the Clojure bit - do you mean STM?

~~~
pron
Well, I'm used to developing multi-MLOC projects in large teams; they don't
switch a language so easily...

As for Clojure, I mean this: [http://www.infoq.com/presentations/Value-
Identity-State-Rich...](http://www.infoq.com/presentations/Value-Identity-
State-Rich-Hickey) (basically: immutability, controlled state transitions via
agents/atomic/STM)

------
lmm
As a scala fan:

Sequence literals, intersection types, type aliases, declaration-site
variance, functions and methods? Got them.

Modules? Meh. The OSGi thing has always struck me as hideously overengineered;
I've never understood what problem it's supposed to solve.

Nullable types? The trouble with doing this at the language level is that you
can't then treat them as plain old objects. Can I write a method that's
polymorphicly nullable? Can I write a method that polymorphicly handles
"nullable" or Future or Validation, like scalaz's "sequence"?

Union types? Yeah, proper union types would be good.

~~~
gavinking
> Modules? Meh. The OSGi thing has always struck me as hideously
> overengineered

And that's _exactly_ why you need modularity built into the ecosystem. OSGi
and Maven _are_ hideously overengineered, and they're overengineered because
there's no common model built into the language, toolset, and platform.

> I've never understood what problem it's supposed to solve.

Management of versioned dependencies between libraries and components
developed by different teams. This is absolutely central to what software
engineering is all about.

> Nullable types? The trouble with doing this at the language level is that
> you can't then treat them as plain old objects.

I don't think you've understood what this is. In Ceylon, null is the singleton
instance of the perfectly ordinary class Null. A nullable type is just a union
type of form Null|X, for any type X.

> Can I write a method that's polymorphicly nullable?

Sure. You should see the crazily cool stuff we can do with stuff like the
signature of max(). You'll be impressed, I promise!

After that, check out signatures of operations like Set.union(),
Set.intersection(), coalesce(), compose(), flatten(), curry(), etc, to see a
bunch of other things you just can't write in Scala.

> functions and methods? Got them.

Does scala have toplevel functions? I thought they always had to be nested
inside some object?

But my real big problem with Scala here is it just doesn't have proper
function and tuple types that you can abstract over. Instead you have F, F1,
F2, F3 ... F22 and Tuple2, Tuple3, ... Tuple22. That to me is just rubbish.

~~~
barkmadley
> > Can I write a method that's polymorphicly nullable?

> Sure. You should see the crazily cool stuff we can do with stuff like the
> signature of max(). You'll be impressed, I promise!

From the docs:

> A nonempty iterable is an iterable object which always produces at least one
> value. A nonempty iterabe type is written {String+}. Distingushing nonempty
> streams of values lets us correctly express the type of functions like
> max():

> {Float+} oneOrMore = .... ;

> {Float*} zeroOrMore = .... ;

> Float maxOfOneOrMore = max(oneOrMore); //never null

> Float? maxOfZeroOrMore = max(zeroOrMore); //might be null

While this is interesting, is it enforced by the compiler? i.e. is the
following a runtime, or compile time error?:

    
    
        Float maxOfOneOrMore = max(zeroOrMore);

~~~
gavinking
> While this is interesting, is it enforced by the compiler?

Of course. That's the whole point. I really think you've missed the nature of
Ceylon. Don't imagine, that just because it has a syntax that looks friendly
and harmless and familiar, that it doesn't have a really killer type system
under the hood.

> i.e. is the following a runtime, or compile time error?

A compile-time error, of course.

~~~
barkmadley
I assume this is the implementation [1](took me a while to find the type to
see how the compiler might interpret it).

I read the definition as (ignoring the implementation):

    
    
        return a Value or Absent when given an Iterable<Value,Absent> where Value is Comparable and Absent is Null
    

Correct me if I am wrong, but there doesn't appear to be anything linking the
nullability of the return value based on the possible emptiness of the input
value. How does the compiler check this constraint (which sounds a lot like a
dependent type relation)?

Upon further reading of the Iterable type[2], I have more questions, does
"Nothing" satisfy "Null"?

| If not, then it looks to me like passing in a non-empty iterable
(Iterable<X,Nothing>) is a type error.

| If so then I would imagine that it becomes harder to enforce the constraint,
likely because the return type can still be Null regardless of input
restrictions. Does this use extra type inference on the expressions inside the
function to do the enforcement, for instance using the "exists" operator to
perform type set subtraction between {Value|Null} and {Null} on the true
branch. This implies that if I re-write the max function to have a single exit
point (`ret = Null; if (exists values.first) { ...; ret = ...; } return ret;`)
then I don't get the same guarantees?

Also the fact that Null is referenced by the "exists" operator also implies
that it is part of the language specification, and not actually definable in
any meaningful way as a user type.

Digging a bit deeper, I was very disappointed to read this snippet [3]:

    
    
        Nothing is considered to belong to the module ceylon.language. However, it cannot be defined within the language.
    

If I read correctly, that means that I cannot implement the same
behaviour/enforcement with completely user defined types.

[1]: [http://modules.ceylon-
lang.org/repo/1/ceylon/language/1.0.0/...](http://modules.ceylon-
lang.org/repo/1/ceylon/language/1.0.0/module-doc/max.ceylon.html)

[2]: [http://modules.ceylon-
lang.org/repo/1/ceylon/language/1.0.0/...](http://modules.ceylon-
lang.org/repo/1/ceylon/language/1.0.0/module-doc/Iterable.type.html)

[3]: [http://modules.ceylon-
lang.org/repo/1/ceylon/language/1.0.0/...](http://modules.ceylon-
lang.org/repo/1/ceylon/language/1.0.0/module-doc/Nothing.type.html)

~~~
gavinking
> Correct me if I am wrong, but there doesn't appear to be anything linking
> the nullability of the return value based on the possible emptiness of the
> input value.

Sure there is. The second type parameter of Iterable encodes that, see the
definition of Iterable.

> does "Nothing" satisfy "Null"?

Of course. Nothing is the bottom type, it satisfies every type.

> If so then I would imagine that it becomes harder to enforce the constraint,
> likely because the return type can still be Null regardless of input
> restrictions.

I don't know what you mean by this. An Iterable<X,Nothing> cannot return Null
from its first attribute. Check the declaration of Iterable.first.

> Does this use extra type inference on the expressions inside the function to
> do the enforcement, for instance using the "exists" operator to perform type
> set subtraction between {Value|Null} and {Null} on the true branch.

Approximately correct. But "exists" is not type subtraction, it's intersection
with the class Object. Cool, huh?

> This implies that if I re-write the max function to have a single exit point
> (`ret = Null; if (exists values.first) { ...; ret = ...; } return ret;`)
> then I don't get the same guarantees?

I don't follow. You can't rewrite the function to do anything unsound because
the compiler won't let you. Our type system is sound.

> Also the fact that Null is referenced by the "exists" operator also implies
> that it is part of the language specification, and not actually definable in
> any meaningful way as a user type.

That's not correct. Go and check the definition of Null. It's just a regular
class, as advertised. There is no special behavior defined in the language
spec. Sure, the exists operator is defined by the language spec to mean "is
Object", but that's just trivial syntax sugar.

I guess the problem here is that you're used to languages full of weird
special cases and ad hoc behavior. Ceylon is not like that. Ceylon's type
system is very simple and these fancy constructs are layered over it as pure
syntax sugar. It's a very different approach to other languages. But in the
end it's much more satisfying. You'll just need a little mental adjustment to
get used to it.

> If I read correctly, that means that I cannot implement the same
> behaviour/enforcement with completely user defined types.

Wha?! Nothing is the bottom type! The empty set. You want to define your own
bottom types? That's not possible (nor desirable) in any language I know of.
There's just no reason why you would want to write a class with no instances.

~~~
barkmadley
> I don't know what you mean by this. An Iterable<X,Nothing> cannot return
> Null from its first attribute. Check the declaration of Iterable.first.

This made me sad again[1], but then this made me happier[2] (internalFirst
implied it is defined in the compiler, finding all of the pieces that make up
the definition was a bit of a pain since it is dispersed across so many
files), but I think I didn't fully understand union types (and that Nothing
was bottom) when I wrote the grand parents logical conclusions.

    
    
        :t Iterable<X,Nothing>.first ==>
           X|Nothing ==>
           X (because union with empty is an identity)
    

therefore inside max, the variable first will have type X when given an
Iterable<X,Nothing>.first. I also see how it cannot be re-written as I
proposed because there is no guarantee that Absent will be of type Null.

> That's not correct. Go and check the definition of Null. It's just a regular
> class, as advertised. There is no special behavior defined in the language
> spec. Sure, the exists operator is defined by the language spec to mean "is
> Object", but that's just trivial syntax sugar.

I did check the definition of Null, I was merely pointing out that although it
is a user definable type, the language specification does mention its
existence here[3] and here[4] which is where I looked to try to find out what
the "exists" keyword meant. Specifically:

    
    
        in the case of an exists condition, a type whose intersection with Null is not exactly Nothing and whose intersection with Object is not exactly Nothing, or
    

Later on it says "exists x is equivalent to is Object x, and..." but then why
reference Null earlier?

> I guess the problem here is that you're used to languages full of weird
> special cases and ad hoc behavior.

While I thank you for your time answering my mis-understandings of union
types, please do not shoe horn me. My main programming activities are using
OCaml and Haskell, both of which have very few ad-hoc language features, if
any.

[1]: [http://modules.ceylon-
lang.org/repo/1/ceylon/language/1.0.0/...](http://modules.ceylon-
lang.org/repo/1/ceylon/language/1.0.0/module-doc/Iterable.ceylon.html#130,133)

[2]:
[https://github.com/ceylon/ceylon.language/blob/master/src/ce...](https://github.com/ceylon/ceylon.language/blob/master/src/ceylon/language/first.ceylon)

[3]: [http://ceylon-
lang.org/documentation/1.0/spec/html_single/#c...](http://ceylon-
lang.org/documentation/1.0/spec/html_single/#compiletimesafety)

[4]: [http://ceylon-
lang.org/documentation/1.0/spec/html_single/#a...](http://ceylon-
lang.org/documentation/1.0/spec/html_single/#assignabilityexistencenonemptinessconditions)

~~~
gavinking
> I was merely pointing out that although it is a user definable type, the
> language specification does mention its existence

Sure, the language spec _mentions_ Null, in order to define the syntax sugar
X? and exists x. But that doesn't mean that Null has any special place _in the
type system_.

> My main programming activities are using OCaml and Haskell, both of which
> have very few ad-hoc language features, if any.

OK, great, sorry for making assumptions. In my defense, I just didn't quite
understand why you were having such a hard time believing that Ceylon could do
things like this without adhoc special cases.

------
terranstyler
IMO, the article lacks a comparison to the functional elephant in the JVM
room.

~~~
timclark
Would that be clojure?

~~~
terranstyler
Yes, just to elaborate:

The improvements over Java are things addressed in (typed) clojure.

I get the feeling that comparing Ceylon to Java is like comparing a 1990s car
against a 1980s car. That's not to say the comparison is invalid but if (and
only if) the goal is to have/make/evaluate a good car you should compare it to
2010s cars.

~~~
RivieraKid
I really enjoyed programming in Clojure, especially 4clojure.com, an amazingly
fun way to learn a new language.

But I think that I would be similarly productive in it (or perhaps less) than
in Java even after let's say 1 year experience because of:

* Worse readability (parens, less regular). That's the #1 problem of Clojure.

* IDEs, including LightTable, are not even close to the usefulness of Eclipse or IDEA.

* Imperative code is easier to write and more importantly more readable in Java.

* Formattig code for readability is PITA. In Eclipse, I usually just press Ctrl+Shift+F to autoformat after every edit.

~~~
pron
I develop mostly in Java with quite a bit of Clojure. While my favorite IDE is
NetBeans, when I work on a mixed Java/Clojure project I use IntelliJ IDEA with
the Cursive[1] plugin. You can freely jump from a Clojure call to Java code,
and when you rename a Java method, it refactors the Clojure code as well.

[1]: [http://cursiveclojure.com/](http://cursiveclojure.com/)

~~~
pjmlp
Sadly Enclojure is now dead.

------
modersky
Just wanted to say that I think union and intersection types are very
interesting and powerful. Also agreed on the fact that Tuple22 and friends are
not ideal. We are looking for ways to avoid that in a future version of Scala.
I am certainly very interested in what you and the Ceylon community do in
terms of language design and hope we can learn from each other.

~~~
gavinking
Cheers, Martin, thanks for the note, I appreciate it! Well, there's already a
couple of things we learned from you guys: FTR, Scala was the first place I
ever saw declaration-site variance, which rocks. It's also the language that
influenced me and the others to take type inference seriously. Definitely hope
it's a two-way street :-)

------
jeff303

      What does one do when Hibernate is “finished” and feature complete and one needs new challenges?
    

Maybe implement this? :)

[https://hibernate.atlassian.net/browse/HHH-1050](https://hibernate.atlassian.net/browse/HHH-1050)

------
Uchikoma
Minor point: Nullable types and Maybe are two completely different things,
which can be used for some overlapping use cases.

~~~
mhaymo
I don't understand the difference, and a quick search turned up nothing. Care
to educate?

~~~
timclark
There is no major difference between a nullable type and a maybe - the big
difference is between non-nullable types and maybe. If you have a maybe I in
my ignorance can assign a null to it, if you have a non-nullable type the
compiler will prevent me from assigning a null to it.

~~~
mhaymo
Ok, so in a default non-nullable type system, nullable types are equivalent to
maybes.

~~~
pestaa
As far as I can tell, you are right, although in my view maybes are one step
ahead: they form a monad. (Not saying there's anything stopping you from doing
the same thing with nullables, but still they're a slightly different
concept.)

------
kasey_junk
Union & Intersection types are such a big deal that they alone are enough to
make me want to play with Ceylon.

~~~
RivieraKid
Agree, imho the killer feature of Ceylon.

