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 |
|
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
|
|
|
07. Jul 2011
|
|
|
09. Jun 2011
|
| Contexts and Dependency Injection | (44) |
| Ceylon | (41) |
| 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 |
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.
Haha! Try compiling this Java code:
interface Interface<T> {}
class Bang<T> implements Interface<Interface<? super Bang<Bang<T>>>> {
static void bang() {
Interface<? super Bang<Byte>> bang = new Bang<Byte>();
}
}
(For me, the compiler stackoverflows, and Eclipse asks for my permission to crash.)
I'm not sure how widely known this problem is. It's not really a bug in the compiler, more like a bug in Java's type system. I found out about it from this excellent paper, which also proposes a solution to the problem, but the paper appears to build on work in this other paper, which I'm also linking because I'm a big fan of Stefan Wehr's work on JavaGI.
UPDATE: Here's another paper dealing with this issue, this time from Microsoft guys.
And, in case you're wondering, yeah, I can make the Ceylon typechecker stackoverflow with the equivalent code:
interface Interface<in T> {}
class Bang<T>() satisfies Interface<Interface<Bang<Bang<T>>>> {}
void bang() {
Interface<Bang<String>> bang = Bang<String>();
}
I guess ima gunna get right on to implementing the solution proposed in Tate et al.
This is a gorgeous, perfect example of precisely how not to engage in debate over technical issues. I won't respond point-by-point, because the post is mainly self-refuting, but it does amuse me to highlight the following:
- Vague accusations of dishonesty in the title, which are never actually supported in the post itself.
- The claim that projects which were announced to the community approximately three months ago are
vaporware
. (That's the fastest progression from announcement to vapor in history!) - The absurd accusation that people working an alternatives to Java have a secret ulterior motive to actually reinforce the status quo. Yes, seriously.
- Further unsupported accusations of
intellectual dishonestly
, though it's not precisely clear on whose part. - Misattribution / invention of staw man arguments. (To the best of my knowledge none of the teams advocating alternative JVM languages have ever claimed that Scala is
too academic
ortoo functional
ornot functional enough
.) - Insults directed at the entire Java programmer community.
- No actual substantive technical arguments for or against any particular language.
The most ironic thing about this amazingly incivil flamebait post, is that after throwing around accusations of dishonestly and secret agendas, the poster (can't be bothered checking his name) writes:
If you plan to comment, keep in mind that your comment should be constructive and civilized.
Wow. I guess he at least deserves credit for chutzpah. :-)
(I'm closing comments since I can't be bothered responding to the inevitable trolls.)
P.S. Accusations of dishonesty, or of misinformation
(which, in case English is your second language, means deliberate lying
) have been a recurring theme lately. You guys need to put that one to rest. It's not reasonable to call someone a liar because you disagree with them.
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.
In connection with this discussion it's worth making explicit what I guess everybody knows, but that sometimes seems to get a bit mixed up in conversation: that Java's support for raw types (necessary for backward compatibility with pre-generics code) doesn't really have anything much to do with type argument erasure. In a hypothetical language:
- you could have raw types without type argument erasure, or
- you could have type argument erasure without raw types.
Raw types have their own problems, of course (they're a designed-in hole in the type system). But a defense of the existence of raw types does not amount to a defense of partially reified types.
| Showing 1 to 5 of 250 blog entries |
|
|