Hacker News new | past | comments | ask | show | jobs | submit login
Ceylon: Quick introduction (ceylon-lang.org)
154 points by mintplant on July 5, 2014 | hide | past | favorite | 75 comments



I was wondering how Ceylon is supposed to be different from Scala. I found this blog post from 2011 that compares Scala, Ceylon, and Kotlin: http://blog.lunatech.com/2011/08/24/scala-ceylon-kotlin-goal.... Basically, Scala aims to be concise and “scalable” by explicitly aiming for both OOP and FP support. Ceylon aims to be an improved Java that is more concise, powerful, and modular, while still being familiar. Ceylon also aimed to be less complex than Scala while still being as powerful, but I don’t know if it has succeeded.

There is also this huge 2013 article comparing eight JVM languages with each other: http://zeroturnaround.com/rebellabs/the-adventurous-develope...


I really like the look of kotlin, but is there a release date for 1.0?


I've heard Q4/2014 thrown around. I wish Jetbrains updated their Kotlin blog more often than every 2-3 months.


I think they are intending to start seriously using it in production at JetBrains this summer (i.e. now) with a 1.0 stable end of the year?


I think the issue with these comparisons is that they commit the "all languages are equal" fallacy in what seems to be an effort to be "fair" and trying to find good and bad points for every language.

In the end, only actually using the languages helps...


In the same space there is Haxe http://haxe.org/ . It's also an Algol-like language that targets both JavaScript and Java (and flash, c++, .net, php).


Haxe has a few more language features (abstract types) and compiler features (dead code elimination) but it lacks a few from Ceylon such as union types.

The Haxe compiler is much, much faster than Ceylon. I wonder if certain features just can't pass a speed threshold.


haxe's enums seem like full-fledged union types: http://haxe.org/manual/types-enum-instance.html


There's also Ceylon's enumerated subtypes, which look similar: http://ceylon-lang.org/documentation/1.0/introduction/#enume...

However, Haxe's algebraic data types are really not the same thing. It takes a bit more code to achieve an identical effect. On the other hand, algebraic data types are much more general purpose, and allow techniques like pattern matching.

http://en.wikipedia.org/wiki/Algebraic_data_type http://haxe.org/manual/lf-pattern-matching-introduction.html

In the case of Haxe, you can construct a pattern that uses guards and/or extractors (e.g., a pattern that matches cases where you have an empty Tree, or a tree that contains a specific Node. You could also do matches on structural subtypes, etc.)


From the language specification[0]:

> This code is not legal, since all three statements occur in the initializer section of the class body:

    class Point() {
        Float x => y;  //compiler error: y is not referenceable
        Float y => x;
        Float->Float xy = x->y;
    }
> However, this code is legal, since the statements occur in the declaration section of the class body:

    class Point() {
        Float x => y;
        Float y => x;
    }
If I'm reading things correctly, class declarations are split up into "initializer" and "declaration", with only an implicit split (the last statement that is not allowed in the declaration section). This seems very awkward.

0: http://ceylon-lang.org/documentation/1.0/spec/html_single/#r...


It's not that awkward, C# does the same thing:

   interface IPoint
    {
   // Property signatures: 
   int x
   {
      get;
      set;
   }

   int y
   {
      get;
      set;
   }
   }
(taken from http://msdn.microsoft.com/en-us/library/87d83y5b.aspx)


I don't see the similarity. The Ceylon feature I find awkard is that class definitions have two parts (initializer/declaration) with different semantics, without explicit demarcation.

In the example above, this code:

    class Point() {
        Float x => y;
        Float y => x;
    }
is fine, because both declarations are parsed as being in the declaration section. However, when you add another line after that:

    class Point() {
        Float x => y;  //compiler error: y is not referenceable
        Float y => x;
        Float->Float xy = x->y;
    }
The original two declarations are now part of the initializer section, because the third line is a statement that is not allowed in the declaration section. This changes the semantics of the first two lines.


FTR, the whole declaration section vs initialization section stuff really boils down to this:

    You can't declare mutually-recursive methods before 
    initialization logic in the body of a class. You have to 
    declare them _after_ the fields of the class are fully 
    initialized.
That's not so hard to understand.

To see why it's like this, you need to consider :

- Unlike most OO languages Ceylon statically _guarantees_ that a field of an object is initialized before it is accessed. (If we didn't, then we would have to have something conceptually equivalent to a NullPointerException when you access a field before initialization.) - We've always hated the amazingly repeaty syntax of constructors in C++/C#/Java.

What I mean is, in Java I have to write stuff like:

    class Point {
        final float x; 
        final float y;
        Point(float x, float y) {
            this.x = x;
            this.y = y;
        }
    }
In Ceylon, it would be:

    class Point(Float x, Float y) {}
And even with all that verbosity in the Java version, I _still_ don't get a static guarantee that `x` and `y` are initialized before they are used by a method. This code prints `0.0`:

    class Point {
        final float x; 
        final float y;
        Point(float x, float y) {
            fun();
            this.x = x;
            this.y = y;
        }
        void fun() { System.out.println(x); }
        public static final void main(String[] args) {
            new Point(1.0f,2.0f);
        }
    }
So Ceylon wants to solve _both_ these problems: eliminate the verbosity, and provide the static checking for initialization. Now, this is an _almost_ completely transparent process. I almost never find myself thinking about declaration section vs initialization section. I just write classes so that fields are initialized before the methods that use them are declared. Which is basically super-intuitive. In >95% of classes that's all you need to know. Very rarely, I mix this up, and the compiler complains and I need to move a member up or down. Which takes seconds to fix. Very, very rarely, I have a class with some kind of self-recursive initialization logic and then only in that case do I need to start holding the mental model of declaration-vs-initialization sections in my head. In practice, I think I've only run into this situation _once_, and it took me a few minutes to restructure the code. (FTR, it was `ArrayList` in `ceylon.collection`.)


Seems like a bug.


Seems like Gavin King of Hibernate fame is leading this project.


I don't see how that is supposed to be any recommendation. If Ceylon is going to be similar to Hibernate in terms of quality, simplicity, performance and amount of design WTFs, I don't want to touch it.


Too be fair, Hibernate was a whole lot leaner when Gaving was leading the project. And Hibernate was one of the first ORMs, so he was at least pioneering a field, even if the idea admittedly turned out to be less great than initially thought.

And while working on CDI and Weld, Gaving really was the one who pushed for "plug and play" in JBoss, mediating between departments and making sure stuff got usable and in some cases even quite fast. In the end, the Seam guys more or less abandoned EJB and more or less started the POJO trend.

Additionally, I thing that Gavin was one of the first to spot where Hibernate was heading and started to work on ceylon quite early (I forgot when). And if you read what he has written you can tell that he knows his stuff!

You have to give the guy some cred!


I've been bitten by Hibernate and Seam badly. Although Ceylon might be cool, I've got reservations to take a look at it seriously. Not exactly because it is Gavin's work but because I am in no rush anymore to use bleeding edge to enthusiastically wreck myself over.


Well, not sure. When he started Ceylon, he wasn't even aware of the existence of Scala.

Kind of reminds me of the quote from the Groovy creator.

Seems like most of the JVM languages these days are created because people are too lazy to research the state of the art...


Or... the other projects need to do a better job of marketing to raise awareness in the first place?


Just pointing it out, not an endorsement of any sort. I for one was relived and greatly thankful for Hibernate when it appeared on the scene dominated by J2EE and EJB's but thats a discussion I don't want to have in this thread.


I like the direct approach to Union and Intersection Types.

I wonder if the goal of making the language 'immediately readable to people who aren't Ceylon programmers' limits them too much. This might be why the type signature for functions in `void repeat(Integer times, void iterate(Integer i))` is so macabre.

Tuples and comprehensions are always nice. The 'tree syntax' stuff seem a lot like JSON-javascript, which I guess has found it useful.

At the end of the day I'm not convinced why this is a better language than the lot of JVM languages out there.


Ceylon looks very interesting. The union type is a brilliantly simple way to combine types. It's something that once you've seen it you would ask how come type combination not done this way all along.

The map comprehension is very interesting, going beyond list comprehension. Should make functional style programming easier.

I wonder how big the download of the runtime is for running as Javascript inside the browser.


Python has map comprehensions like this:

    {i: i+1 for i in range(10)}
Works pretty well.


Perhaps more comparable to the comprehensions shown in this post would be generator comprehensions:

    list(p.first_name + " " + p.last_name for p in people)
    dict((p.first_name + " " + p.last_name, p) for p in people)
    set(j.organization for p in people for j in p.jobs)
    print(", ".join(p.first_name + " " + p.last_name for p in people))
(Of course, Python has sugar for the first three.)


What's the sugar for the third?


    set(j.organization for p in people for j in p.jobs)
    {j.organization for p in people for j in p.jobs}
The latter is available from Python 2.7+.


The verbosity of reserved words seems like it would get annoying quickly, both in writing and readability("shared actual X"? C'mon!).

I think that conflating clarity of keywords with the clarity of language is a huge and pointless confusion, especially when touting metaprogramming, comprehensions and variadic function arguments.

It doesn't look like a bad language; its features seem well rounded, yet there's a lot of stuff out there that's both more capable, with features that are more orthogonal. There's less feature mishmash than Scala, certainly, but it doesn't seem that far up in the power spectrum to justify learning another language, especially when compared to Kotlin, its closest competitor.

Kotlin just seems to be better in most regards: much more compact syntax, similar features set without some of the questionable overhead of Ceylon, and extension methods.


> If these code examples look boring to you, well, that's kinda the idea - they're boring because you understood them immediately!

This sales pitch finds me at home!

Also there seems to be some nifty features in there e.g native unions and intersections.


Just so you know, Ceylon is a name of a country (now known as Sri Lanka). The name is more popular due to the tea which is manufactured in Sri Lanka (Ceylon Tea)


I've been poking around the site and there was a mention of running in the browser. I have been unable to find any examples. Does anyone see any?

I'm thinking of something modifying form text boxes or something simple like that.


There's a bit about it on the linked page (look for the description of "dynamic" blocks), plus a tutorial on their blog: http://ceylon-lang.org/blog/2013/02/26/ceylon-in-the-browser...


There is a REPL here: http://try.ceylon-lang.org/


Why is that we need new languages? Why not improve existing languages? We, as a community, would benefit from solving the very limitations that lure developers into other languages.


Because that would break backwards compatibility.


I don't think that's the right argument. Re-writing few parts or writing entire app in new lang, which one would be better for app developer?


If only you could write a new service in a different language and then make requests to it... oh wait, you can!

At my last job we had a Node.js app talk to a Scala backend and the other end of the system ran PHP. I mean we already had like 30 servers at least, so dedicating one to Node and a few to Scala wasn't a problem.


I see that immutability is not a first-class citizen in this language... mmmhhh....


It actually seems to default to immutability, and have mutability as a first-class citizen with the language annotation `variable`: http://ceylon-lang.org/documentation/1.0/tour/attributes-con...

I'm not sure if it's quite as flexible as C++'s const-correctness, but if you're creating your own class hierarchy from scratch, you can (and are encouraged to) code in a style that basically ensures that every parameter is practically passed as a const (immutable) reference. So you can easily do things like make strongly-typed functional data structures that will compiler-complain if you try to modify them after creation, without needing to remember to type "const" all the time. And that's realistically what most people need at the end of the day.

I'm excited to experiment with this - it seems definitely designed by pragmatists who want to lower the barrier to entry and make it fun for non-functional programmers to code in (I'm looking at you, Haskell), but also encouraging and enforcing best practices wherever possible.


When I wrote my comment, I was actually looking at how variables inside a method are declared, not fields (attributes, as they call it in this language) like you mention (seems like the 'variable' keyword is not for local variables, but for attributes).

So I was mainly hoping it is like F#, that forces you to decorate non-immutable variables with the `mutable` keyword, inside a method/function.

However, thinking about it more deeply, this is not so important. Because local variables (in a method) are never shared between threads. So immutability doesn't suffer from them being mutable. Right?


Probably right. One of the Rust developers suggested something similar (but more nuanced, because Rust is a highly nuantial language):

http://smallcultfollowing.com/babysteps/blog/2014/05/13/focu...

"Put another way, it’s become clear to me over time that the problems with data races and memory safety arise when you have both aliasing and mutability. The functional approach to solving this problem is to remove mutability. Rust’s approach would be to remove aliasing."

Local variables themselves are naturally non-aliased, although the objects they point to might be.

PS apologies to anyone who's seen it before for trotting that link out yet again!


In Ceylon even local variables must be explicitly annotated `variable`.

The reason for that is that a local variable could be captured by an anonymous function or nested function, and escape from the local scope, so it's exactly the same situation with a local variable as for an instance variable of a class: both kinds of variable break referential transparency.


Immutability is kind of an overrated fad. The world is very much mutable. I want to see how languages manage mutability. Languages that provide simple mechanisms and tools to manage mutability go a long way to help the programmers to cope with the real problems.


> The world is very much mutable

This depends on your definition of "the world". If time and memory are taken into account, you could easily make the case that the world is very much immutable. For example, if your friend changes his email address, its not as if his old address no longer exists. Even if it only exists in memory, it still exists somewhere, and you're still able to reference it.

If you're interested in this topic, I highly recommend Rich Hickey's talk "The Value of Values"[1].

[1] http://www.infoq.com/presentations/Value-Values.


In that case, the reference is still mutable even if the email address isn't. One may also delete an account; i.e. you can change the state of something. A language should set clear boundaries on what is mutable or not, and I see both FP and IP languages going with extreme boundaries in either direction.


Immutability is an excellent tool to manage mutability. It lets you make guarantees about what won't change, which allows for some really great optimisations - like safe cross-thread reads without locks.

I agree it's not right for everything, but there are a lot of operations that can be modelled with immutable data, such as most server-side web code - reads definitely, and a lot of the write operations don't actually need to mutate objects though most ORMs and other DB APIs do require this.


Mutability is a great tool; it dramatically simplifies certain algorithms, and dramatically improves performance of others. But it comes at a cost, and there are situations in which it is inappropriate. So the language should force you to think before reaching for this tool. It shouldn't be the default tool for every problem.


> The world is very much mutable.

LOL, what?


Depending on your concept of time, it very much is. If you choose the same abstraction of time for reasoning about the program state and the real world, the same "reference" might change its properties over time. The speed of a car is mutable over time. The question is if the way we reason about time when talking about the "real" world is appropriate for reasoning about time in programs.


Attach a date stamp to your references and facts and BOOM, everything is immutable!


Yes, you mention it. Time.

Time is a real property just like IO, effects, values and types. If people stop hand-waving, we would have fewer bugs.


The recent profileration of languages amazes me. Every major computing house now has one or more programming languages. Is this a strategic approach to reign the future.? Or has it become easier to design languages. Thinking of how little Java helped Sun to escape disappearing I m curious of the opinions of people in charge..

Ps: welcome again Ceylon, hope you'll give RedHat a brighter future in the enterprise.


It's not that recent. I used to spend hours pouring over shareware/ pd collection catalogues back in the 80's, mostly looking for interesting new languages.

From late 80's to mid 90's (I think) there was even a magazine called Computer Language that focused almost exclusively on writing about different programming languages.

It was common to see articles about writing compilers and interpreters for your own languages in various magazines. One Amiga magazine I picked up in 1990 in Germany included a listing for a full (tiny) compiler for a Pascal inspired language.


We've been here before. This seems to occur in cycles. It will soon burn out, and then we will see a plethora of operating systems. A period of relative stability will occur, and the cycle will begin again.


What is a language? How deeply up and down the abstraction scale does a "language" need to implement to be called a language?

Some languages, like Go, implement a different edition directly atop many various OS's, with their own garbage collection and type inference. Whereas others, like Coffeescript, are text generators sitting atop and relying on features of other languages. And there's many shades in between, such as languages that produce JVM bytecode rather than executables for each different hardware target the JVM sits atop.

Then there's the issue of how much support atop the text files a language directly supports. Some, like Kotlin, make IDE support an official policy, whereas others, like Java, don't, instead relying on third parties to provide it. Some languages only provide the visual interface. Macros, like in Clojure, and compiler directives, like in C, could also be considered "atop the text file syntax".

If readable source code in some certain language can be generated from a VM or an AST that many different "languages" target, then in a sense they're not really languages at all, only "bytecode generators" or "transpilers".


This is a very good question. Unix/C came from the glorious "system building" era. They took responsibility for building and documenting "the whole stack" - from assembly to signals to troff. Wirth's Oberon OS/language were codesigned in the same fashion. Smalltalk/V took over a PC.

Ceylon seems like a very nicely designed language (and I don't mean syntax). I would love to see a LLVM back end and the requisite docs for low level system hacking.


The beating of web programmers with new languages will continue until morale improves :-) I mean, until somebody figures out that the HTML/CSS/DOM etc make the task nearly impossible, no matter what language.


Oddly, I think the problem is orthogonal. Mayhap that isn't the correct word.

Regardless, my assertion is that the problem is when most of us write web apps, we think of it as a single application. Frameworks often make this worse, as half of them treat the goal as to hide that you are writing a distributed application.

Contrast this with what is really going on, where you have -- at a minimum -- a front end and a backend operating independently of each other. And I'm not just talking multithreaded. They are literally completely disconnected from each other.

So, consider how we use all sorts of paradigms to try and make writing a multithreaded program easier. Now, consider at the end of the day many of these tasks can be done with simple locks and semaphores. Better yet, consider that most of the higher abstractions build on those.

Now, when is the last time you saw a tutorial for using a semaphore between an html front end and a backend?*

* I'm really hoping someone proves me wrong on this question. :)


But they are disconnected, one is running on the client, the other on the server. Regardless of any magical unified framework, there will be two processors talking asynchronously over network protocols. GWT does this kind of integration and it's far from a panacea.


Apologies for poorly making that point. That is, my point was that we need more ways to embrace this separation. I'm not sure unifying the language on client/server would really help.


I would say that many if not most of the issues in front-end webdev have been / are being fixed (web components, flexbox). Supporting non-evergreen browsers (ie. IE < 11) is what makes the task difficult in my opinion.


Note that it's not just a "web" language. It runs on the JVM (as well as in the browser), and can be used as a more featureful Java replacement. To this end, it has very nice interop support with Java [1], helped by their similar syntax/structure.

[1] http://ceylon-lang.org/documentation/1.0/reference/interoper...


> A new language

Version 0.1 was released on Dec 20 2011 : http://ceylon-lang.org/download-archive/ .


The first production-ready version was released in late 2013: http://ceylon-lang.org/blog/2013/11/12/ceylon-1/

The language is still relatively new, and under active development: https://github.com/ceylon


Thanks. I'm not sure how we missed that one.

We've changed the submitted title (which was "Ceylon: A new language by Red Hat for the JVM and the browser") to the article title.


Misleading Title


How come it is a new language if the version 0.1 was around 3 years old.? In that sense i should call Python 2.7.8 a new language which was released a week back.


>Ceylon's syntax is ultimately derived from C. So if you're a C, Java, or C# programmer, you'll immediately feel right at home

...yet we introduce the VB-keyword "shared" instead of "public", "variable" instead of C#'s "var" and use square brackets instead of curly braces for array initialization. You know, just because fuck you.

Seriously I see this all the time in new languages. Why invent or change keywords just for the sake of changing? Why does Rust use "let"? Why does Scala use "def"? If you want easy adoptation from one of the two largest languages in the world, change what matters and stick with the rest.


> Why does Rust use "let"?

let is the standard keyword for introducing a new, shadowing variable binding. It is a very old tradition and is immediately recognizable to functional programmers.

> If you want easy adoptation from one of the two largest languages in the world, change what matters and stick with the rest.

In the case of "let", it would be a false consistency with C/Java. Assignment in C/Java does not have the same semantics as a let binding in Rust, although a let binding in Rust has very similar semantics to a let binding in Scheme or Haskell.


C — the language he cites as inspiring the syntax — doesn't have "var" or "public," so you're arbitrarily choosing another language as the "starting point" and then insulting this language for not doing the same thing as the one you would have chosen. And in the years since C came about, square array literals have been pretty common (and curly-brace array literals are actually almost unheard-of)†, so that seems like a pretty reasonable deviation from C.

† Here is a not-remotely-exhaustive list of languages with square sequence literals: D, Objective-C, Python, Ruby, JavaScript, PHP, the whole ML family, Clojure. On the other hand, C didn't even traditionally have array literals — it just had a special curly-brace initializer syntax you could use with arrays as well as other aggregates.


To add to your list of languages with square-bracket array/list/vector initializers (see also [0]): Aikido, Coffeescript, E, F# (sorta, uses pipes too), Groovy, Haskell, Matlab, Nimrod, Postscript, Vimscript.

[0]: http://rosettacode.org/wiki/Arrays


Yeah, let goes back at least 40 years: http://en.m.wikipedia.org/wiki/ML_(programming_language)


Longer, LISP had it in 1958, a full 56 years ago.


because you shouldn't confuse people by naming things the same when they are different


Exactly, thanks!




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: