I'm the creator of Hibernate, a popular object/relational persistence solution for Java, and Seam, an application framework for enterprise Java. I've also contributed to the Java Community Process standards as Red Hat representative for the EJB, JPA, JSF specifications and as spec lead of the CDI specification. At Red Hat, I'm currently working on Ceylon, a new programming language for the JVM.
I also post stuff on G+.
| Recent Entries |
|
20. Mar 2012
|
|
|
26. Feb 2012
|
|
|
10. Jan 2012
|
|
|
12. Aug 2011
|
|
|
11. Aug 2011
|
|
|
06. Aug 2011
|
|
|
02. Aug 2011
|
|
|
01. Aug 2011
|
|
|
24. Jul 2011
|
|
|
22. Jul 2011
|
|
|
21. Jul 2011
|
|
|
20. Jul 2011
|
|
|
19. Jul 2011
|
|
|
17. Jul 2011
|
|
|
13. Jul 2011
|
| Contexts and Dependency Injection | (44) |
| > Ceylon < | (43) |
| Web Beans | (41) |
| Seam News | (29) |
| Seam | (28) |
| Weld | (14) |
| Java EE 6 | (13) |
| Introduction to Ceylon | (12) |
| Hibernate | (6) |
| JavaServer Faces | (6) |
| JPA | (5) |
| JPA 2 | (5) |
| Web Beans Sneak Peek | (5) |
| Criteria Queries | (4) |
| Bean Validation | (3) |
| EE6 Wishlist | (3) |
| Portable Extensions | (3) |
| Seam Wiki | (3) |
| Web Frameworks | (3) |
| Interceptors | (2) |
| JBoss Tools | (2) |
| Payasos | (2) |
| XML Hell | (2) |
| Ceylon IDE | (1) |
| EJB | (1) |
| Granite DS | (1) |
| JDO | (1) |
| Persistence | (1) |
| Photography | (1) |
| RichFaces | (1) |
|
Java Persistence with Hibernate
with Christian Bauer November 2006 Manning Publications 841 pages (English), PDF ebook |
|
Hibernate in Action
with Christian Bauer August 2004 Manning Publications 408 pages (English), PDF ebook |
This is the second release of the Ceylon compiler and other command line tools.
You can read Stef's announcement here at the Ceylon blog. The major new features are:
- Java interoperability
- enumerated/algebraic types and switch/case
- first-class and higher-order functions
- support for remote module repositories and Maven repositories
A huge thanks to the Ceylon team for getting this release done on schedule while I've been taking a break from development! Thanks so much!
Great, I'm finally able to write, compile, and run Ceylon code that uses Java libraries from within Ceylon IDE:
import java.lang { System { sysprops=properties } }
import java.util { Date }
void greet() {
value date = Date();
print("Hello, " sysprops.getProperty("user.name", "world")
", the date is " date.day "/" date.month "/" 1900+date.year ".");
}
This doesn't look like much, perhaps, but it's demonstrating some important features of the interoperability:
- the ability to map a Java static declaration to a toplevel declaration in Ceylon,
- the ability to resolve an invocation to the correct overloaded version,
- the equivalence between Java primitive types and java.lang.String and Ceylon types in ceylon.language, and
- the automatic mapping of JavaBeans properties to Ceylon attributes.
Here's a second working example:
import java.lang { System { sysprops=properties } }
import java.io { File }
void listHomeDir() {
for (file in File(sysprops.getProperty("user.home")).listFiles()) {
print(file.canonicalPath);
}
}
Java interop has been a somewhat tricky problem for us because Ceylon's type system is somewhat different to Java's, and because the design of Ceylon's language module isn't really based on the Java SDK. When running on the Java VM, the language module does make use of the Java SDK as part of its internal implementation. But when running on a JavaScript VM, it can't, of course. So we have to limit our dependence upon JVM-specific stuff.
We've still got a few things to finish off here. For example, our treatment of arrays and Java Iterables is not completely finished, and some IDE features still aren't working quite right, but I think most of the hard work is already done, ready for release as part of Ceylon M2.
Good work guys!
The first official public release of the Ceylon IDE is out! You can read David's announcement here.
This is a full-featured development environment for Ceylon, with I guess everything you use regularly in your Java IDE, including interactive error reporting, incremental build, syntax highlighting, proposals, quick fixes, refactoring, searching, wizards, hover help, debugging, and much more. It even has a major feature that your Java IDE doesn't have: deep integration with Ceylon's module and module repository architecture. (No more futzing with the project build path!)
Check out the feature list, and some screenshots. Then try it out from our update site.
I'll have more to say about how we were able to engineer an entire professional IDE for a new language in less than 6 months with two part-time developers in a future post.
Once again: thanks to David Festal for all his hard work, and to SERLI for their support.
A couple of days ago I spotted an interesting hole in Ceylon's type checker. I started out with something like this:
Sequence<Float>|Sequence<Integer> numbers = .... ; Sequence<Numbers> numbers2 = numbers;
The Sequence interface is covariant in its type parameter. So, since Float and Integer are both subtypes of Number, both Sequence<Float> and Sequence<Integer> are subtypes of Sequence<Number>. Then the compiler correctly reasons that the union of the two types is also a subtype of Sequence<Number>. Fine. Clever compiler.
Now, here's the hole:
value first = numbers.first; //compiler error: member does not exist value first2 = numbers2.first; //ok, infers type Number
When it encountered the union type, the member resolution algorithm was looking for a common produced type of the type constructor Sequence in the hierarchies of each member of the union type. But since Sequence<Float> isn't a subtype of Sequence<Integer> and Sequence<Integer> isn't a subtype of Sequence<Float>, it simply wasn't finding a common supertype. This resulted in the totally counterintuitive (and, in my view, pathological) result that the member resolution algorithm could not assign a type to the member first of the type Sequence<Float>|Sequence<Integer>, but it could assign a type after widening to the supertype Sequence<Number>.
Of course, there might be many potential common supertypes of a union type. There's no justification for the member resolution algorithm to pick Sequence<Number> in preference to a sequence of any other common supertype of Float and Integer. We've got an ambiguity.
So I quickly realized that I had an example which was breaking two of the basic principles of Ceylon's type system:
- It is possible to assign a unique type to any expression without
cheating
and looking at where the expression appears and how it is used. - All types used or inferred internally by the compiler are denoteable. That is, they can all be expressed within the language itself.
These principles are specific to Ceylon, and other languages with generics and type inference don't follow them. But failing to adhere to them - and especially to the second principle - results in extremely confusing error messages (Java's horrid capture-of
type errors, for example). These two principles are a major reason why I say that Ceylon's type system is simpler
than some other languages with sophisticated static type systems: when you get a typing error, we promise you that it's an error that humans can understand.
Fortunately I was able to discover
a useful relationship between union types and covariance.
If T is covariant in its type parameter, then T<U>|T<V> is a subtype of T<U|V> for any types U and V.
But furthermore, T<U|V> is also a subtype of any common supertype of T<U> and T<V> produced from the type constructor T. We've successfully eliminated the ambiguity!
So I adjusted the member resolution algorithm to make use of this relationship. Now the problematic code compiles correctly, and infers the correct type for first:
value first = numbers.first; //ok: infers type Float|Integer
Well, that's great! Oh, but what about types with contravariant type parameters? What type should be inferred for the parameter of the consume() method of Consumer<Float>|Consumer<Integer>? Well, I quickly realized that the corresponding relationship for contravariant type parameters is this one:
If T is contravariant in its type parameter, then T<U>|T<V> is a subtype of T<U&V> for any types U and V.
Where U&V is the intersection of the two types. So the type of the parameter of consume() would be Float&Integer, which is intuitively correct. (Of course, since it is impossible for any object to be assignable to both Float and Integer, the compiler could go even further and reduce this type to the bottom type.)
But, ooops, Ceylon doesn't yet have first-class intersection types, except as a todo
in the language specification. And our second principle states that the compiler isn't allowed to infer or even think about types which can't be expressed in the language!
Well, really, I was just waiting for the excuse to justify introducing intersection types, and this gave me the ammunition I was waiting for. So yesterday I found a couple of free hours to implement experimental support for intersection types in the typechecker, and, hey, it turned out to be much easier than I expected. It's also a practically useful feature. I've often wanted to write a method which accepts any value which is assignable to two different types, without introducing a new type just to represent the intersection of the types.
I'll leave you with two more interesting relationships, applying to intersection types:
If T is covariant in its type parameter, then T<U>&T<V> is a supertype of T<U&V> for any types U and V.
If T is contravariant in its type parameter, then T<U>&T<V> is a supertype of T<U|V> for any types U and V.
Nice symmetries here.
Cedric recently brought up the topic of type erasure, concluding:
All in all, I am pretty happy with erasure and I’m hoping that the future versions of Java will choose to prioritize different features that are more urgently needed
Well, I suppose erasure isn't the thing I hate most about Java, but it's certainly up there. Java's system of partially reified types actually adds a surprising amount of complexity and unintuitive behavior to the type system.
From a pure language-design point of view, I think a partially reified type system is one of the worst decisions you could possibly make. Either reify all types, like C#, or reify none of them, like ML. And look, there's certain language features that simply don't play nicely with type erasure. A case in point: overloading. You can have type erasure, or you can have overloading (or, like Ceylon, you can have neither). You can't have both type erasure and overloading. No, Java is not a counter-example to this! In terms of language design, Java's approach to reification is almost impossible to justify except as a totally half-baked and misconceived workaround for simply not having time to Do It Right.
But Cedric's coming from a purely practical point of view, saying the problems don't actually bite him much when he's doing real work. Well, OK, I can see that. So here's the practical reasons why I think reified generics are needed, and why they should be added to Java if that could be done without messing up Java's type system even further.
Frameworks
Many frameworks depend upon having reified types. Type argument erasure cripples frameworks that work with generic types, and results in horrid workarounds like this one in CDI.
Typesafe narrowing
Instead of a Java-style instanceof operator, and C-style typecasts, Ceylon provides a construct for narrowing the type of a reference in a totally statically typesafe way. You just can't get ClassCastExceptions in Ceylon.
But this functionality depends upon having reified generics. Until we implement reified type arguments, we can't provide any mechanism to narrow to a parameterized type. Right now, you simply can't narrow an Object to a List<String>.
You might think that this is a problem with Ceylon, but really, the situation isn't much better in Java. The instanceof operator doesn't support types with type arguments, and casting to a type with type arguments is a totally unsafe operation! I just don't think that's acceptable behavior in a language with static typing.
Inter-language interoperability
Interoperability between statically-typed JVM languages is going to get really messy when some of the languages support reified generics and some don't. Especially since it's easy to imagine that those languages which do support reified generics won't support them in an interoperable way. This could turn out to be a real problem for the vision of a multi-language JVM.
| Showing 1 to 5 of 43 blog entries tagged 'Ceylon' |
|
|