> Modules? Meh. The OSGi thing has always struck me as hideously overengineered
One of the next versions of Java will ship with a module system. This will likely be good enough and not worth the hassle of having to deal with two competing module systems.
> Sure. You should see the crazily cool stuff we can do with stuff like the signature of max(). You'll be impressed, I promise!
I have looked it, and maybe I'm not seeing it, but it looks like Ceylon is repeating all the things which have been wrong with Comparable in the first place.
Given that Ceylon had a clean sheet to start with, I'm surprised that no better solution has been found.
The signature is intimidating and basically combines the non-extensibility of Comparable with the declaration-site boilerplate of Comparable—with none of its benefits.
- If your type was written by someone who didn't care to implement Comparable, bad luck!
- If the type has a Comparable implementation which differs from what you need, bad luck, too!
- You need the type to be comparable in multiple ways? Again, bad luck!
If any of this use cases came up, it would mean adding a new method which takes an Comparator to all APIs working with Comparable. Leading to more boilerplate and all the pain usually associated with defining Comparators.
Scala has things to complain about, but I think it's hard to claim that they haven't nailed this case down perfectly.
Consider:
case class Person(firstName: String,
lastName: String,
age: Int) extends Ordered[Person] {
def compare(that: Person): Int =
this.lastName compare that.lastName
}
val persons =
Person("Ann", "Miller", 32) :: Person("Bob", "Smith", 17) ::
Person("Charlie", "Miller", 71) :: Nil
val personsSortedByFirstName = persons.sorted
// Person doesn't implement Ordered (Comparable)
// or we want to use a different Ordering?
val orderByAge = Ordering.by[Person, Int](_.age)
val personsSortedByAge = persons.sorted(orderByAge)
None of the drawbacks, all of the benefits!
Additionally, the signature of the sorted method would be much simpler and more readable in Scala, too:
def sorted[T : Ordering] = ...
Compare that to:
shared Element[] sort<Element>({Element*} elements)
given Element satisfies Comparable<Element> => ...
But I guess messing with Comparable as an upper bound is the best thing one can do without typeclasses. :-/
> Instead you have F, F1, F2, F3 ... F22 and Tuple2, Tuple3, ... Tuple22. That to me is just rubbish.
Looking at what you did with Tuples (basically a linked list), I'm not sure that there is a large difference.
Scala's approach seems to be more in line of YAGNI (if you need that 523-Tuple, you should think a bit about your data model) and performance (no pointer chasing, all values are just a method call away).
Anyway, if one wanted tuples-as-linked-lists, one could just use Shapeless' HList library, which has a few benefits over Ceylon's tuples, too, as far as I see:
val hlist = 1 :: "str" :: 42.31 :: 'sym :: HNil
val str: String = hlist(1) // Not possible in Ceylon, afaik
> One of the next versions of Java will ship with a module system.
I certainly hope so, since we always planned to replace JBoss Modules with Jigsaw when that becomes possible. But we still don't know if the Jigsaw module system will be made available for all consumers or just for the JDK itself.
> If your type was written by someone who didn't care to implement Comparable, bad luck! - If the type has a Comparable implementation which differs from what you need, bad luck, too! - You need the type to be comparable in multiple ways? Again, bad luck!
Um, you've totally missed the point. Go and have another look.
And sure, since you bring it up, we can certainly add a version of max() that accepts a comparator function. It would be a method of Iterable, probably.
And sorry, but I can't imagine why I would want or need typeclasses to solve that problem. Sure, I could use typeclasses, if I were a solution in search of a problem ;)
> I'm not sure that there is a large difference.
You can't abstract over tuple and function -arity in Scala. So yes, there's a big difference. Look at the definition of compose() in Ceylon.
> and performance (no pointer chasing, all values are just a method call away).
At the VM level, tuples are represented as arrays. So there is no real performance penalty.
> Anyway, if one wanted tuples-as-linked-lists, one could just use Shapeless' HList library, which has a few benefits over Ceylon's tuples, too, as far as I see:
In Ceylon, without any macro library, you can write:
value tuple = [1, "str", 42.31];
String str = tuple[1]; //totally possible in Ceylon
Seriously dude, _just try it out_, you're desperately searching for reasons to not like this thing! But it really has cool stuff to offer you. Give it a fair chance!
Sure, _of course_ you're going to find stuff in Scala that you can't do in Ceylon. Scala is one of the most huge and complex and feature-rich languages _ever_! But you'll also find plenty of stuff you can do in Ceylon that you can't do in Scala, if you care to look.
> And sorry, but I can't imagine why I would want or need typeclasses to solve that problem. Sure, I could use typeclasses, if I were a solution in search of a problem ;)
Oh, now I'm a bit confused ... are you really saying that you think that the version with the unreadable and cryptic signature, which is non-extensible in any way and repeats all of Java's mistakes is a good solution (or the best solution available in Ceylon)?
> You can't abstract over tuple and function -arity in Scala. So yes, there's a big difference. Look at the definition of compose() in Ceylon.
I just looked at the documentation of it: compose(g,f)(args)==g(f(args))
Wouldn't this just be ...
val list = List(1,2,3)
val f: (List[Int] => Int) = list => list(0)
val g: (Int => Int) = i => -i
(g compose f)(list)
... in Scala? What am I missing?
> At the VM level, tuples are represented as arrays. So there is no real performance penalty.
Nice, so this would be more like Shapeless' HArray then!
> In Ceylon, without any macro library, you can write:
> value tuple = [1, "str", 42.31];
> String str = tuple[1]; //totally possible in Ceylon
Great, that's nice. I just checked it and you are completely correct of course! Is there also stuff for filtering elements by type, mapping, grouping? I couldn't find much in the code.
> Oh, now I'm a bit confused ... are you really saying that you think that the version with the unreadable and cryptic signature, which is non-extensible in any way and repeats all of Java's mistakes is a good solution (or the best solution available in Ceylon)?
I'm saying that it's cool as hell that the following is all well-typed:
And that this behavior makes the slightly cryptic signature of max() worthwhile.
Sure, sure, this is not the most general possible signature for max(), since it is only for types with a natural order. We could and should add some form of max() for comparator functions, which we already have for sorting.
P.S. By the way, there are examples of functions where type classes are nice, for example sum(), where the type class lets you correctly express the sum of zero elements. (But max() is not one of these functions.) So in fact, we would definitely like to experiment with type classes in a future version of Ceylon, especially since the idea probably meshes very nicely with our reified generics.
> What am I missing?
You're missing that the definition of compose() is abstracted over the arity of the second argument function in Ceylon. It's _one_ function, not a different method defined for each Fi type. Which means that I can write similarly-abstracted functions that use compose().
> Is there also stuff for filtering elements by type, mapping, grouping?
Sure. Tuple is a subtype of List, which is a subtype of Iterable, which defines all stream-processing functions. FTR, an [Integer,String,Float] is a List<Integer|String|Float>.
> I'm saying that it's cool as hell that the following is all well-typed:
Ah ok, that's certainly nice. There is a library in Scala though which let's you switch APIs from T to Option[T] to Try[T] to Future[T] to ... with a single import. But I think in a language were nulls are the primary means to encode a missing value, this possibility is nice and makes a lot of sense! (Although I really think it should be investigated how the signatures can be simplified. If you think it's so great (given the constraints Ceylon has, imho yes, it is) it probably makes sense to support this by default and not by making the library author do extra work.)
> You're missing that the definition of compose() is abstracted over the arity of the second argument function in Ceylon.
But aren't you pretty much focusing on implementation details here? If I said “Tuples in Ceylon ... what a mess! Look at this type signature:
” I think you should rightfully call me out on that this is nothing which matters to a user and a developer will pretty much ever see
[Integer, String, Integer]
I think it's kind of the same way for the current Tuple encoding in Scala. One could switch to a better representation and most users probably wouldn't even notice.
And just for the record: I think you have made very convincing points here that Tuples can be handled and I think moving Scala into the direction of HLists/HArrays makes a lot of sense!
Anyway, I have to say that this discussion has been downright pleasant and some of my reservations towards Ceylon, which were fueled by seeing you in some conversations/talks (both in the Hibernate era and in early Ceylon) which left the impression of “wow, what a jerk” (sorry :-/) to me have been resolved with this discussion.
Again, this discussion was very nice, resulted in learning a few new and interesting things and I'm taking nothing but good impressions with me!
I think if both communities took more care to explain the different reasoning, design decisions and philosophies behind the languages when giving talks or on conferences in the future (I saw a few early Ceylon presentations in which I felt Scala's design decisions were unnecessarily misrepresented, but of course the same applies to any Scala presentation if the subject would touch Ceylon, too), this could be a huge win-win situation for both communities. I think the real competitor of Ceylon/Scala is not Scala/Ceylon, but the sad status quo of our industry. If the communities combined their voices to get the message out that there are modern languages and better development approaches existing today, I think this would benefit everyone.
While I'm probably too spoilt by Scala to enjoy programming in Ceylon, I think that especially compared to its current direct competitor in mindshare, Ceylon has a lot of good ideas and tries very hard to give its users the best experience possible, given the constraints you have given yourself when designing the language. With Ceylon, tons of people will learn about the usefulness of union/intersection types in a real-world setting. This benefits our profession as a whole and would certainly not be the case if the language was just some prettified Java (ok, ok, let's not get me started on Ceylon's syntax :-D).
> But aren't you pretty much focusing on implementation details here?
No, not at all, I'm talking about the ability to abstract over things. Can I write a single higher-order function that operates over functions with any -arity? In most languages, no. In Ceylon, yes.
> Again, this discussion was very nice, resulted in learning a few new and interesting things and I'm taking nothing but good impressions with me!
In general, the quality of discussion here is better than in other places.
> I think if both communities took more care to explain the different reasoning, design decisions and philosophies behind the languages when giving talks or on conferences in the future
Sure, but when you have nasty and idiotic twitter stuff poisoning the air, it's hard to expect people to adopt a fair-minded and technical approach to the topic. People should just get off twitter. It's a community-wrecker. There's almost nothing you can say on twitter that rises above the level of insulting.
One of the next versions of Java will ship with a module system. This will likely be good enough and not worth the hassle of having to deal with two competing module systems.
> Sure. You should see the crazily cool stuff we can do with stuff like the signature of max(). You'll be impressed, I promise!
I have looked it, and maybe I'm not seeing it, but it looks like Ceylon is repeating all the things which have been wrong with Comparable in the first place. Given that Ceylon had a clean sheet to start with, I'm surprised that no better solution has been found.
The signature is intimidating and basically combines the non-extensibility of Comparable with the declaration-site boilerplate of Comparable—with none of its benefits.
- If your type was written by someone who didn't care to implement Comparable, bad luck! - If the type has a Comparable implementation which differs from what you need, bad luck, too! - You need the type to be comparable in multiple ways? Again, bad luck!
If any of this use cases came up, it would mean adding a new method which takes an Comparator to all APIs working with Comparable. Leading to more boilerplate and all the pain usually associated with defining Comparators.
Scala has things to complain about, but I think it's hard to claim that they haven't nailed this case down perfectly.
Consider:
None of the drawbacks, all of the benefits! Additionally, the signature of the sorted method would be much simpler and more readable in Scala, too: Compare that to: But I guess messing with Comparable as an upper bound is the best thing one can do without typeclasses. :-/> Instead you have F, F1, F2, F3 ... F22 and Tuple2, Tuple3, ... Tuple22. That to me is just rubbish.
Looking at what you did with Tuples (basically a linked list), I'm not sure that there is a large difference. Scala's approach seems to be more in line of YAGNI (if you need that 523-Tuple, you should think a bit about your data model) and performance (no pointer chasing, all values are just a method call away).
Anyway, if one wanted tuples-as-linked-lists, one could just use Shapeless' HList library, which has a few benefits over Ceylon's tuples, too, as far as I see: