Thursday, December 21, 2006

Mixin interfaces for Java?

Inspired by last Javapolis conference, and many ideas about new Java 7 language features floating around (like eg. closures) I returned back to my dream about mixins in Java.

In fact, when I think about Ruby, there are two main things I like there. These are closures and mixins. If both were added to Java 7, I would be more than pleased.

My idea for mixins would be pretty simple. No new syntax at all. Just use existing language feature - interfaces - and make them a little bit richer. The example mixin could look the following:

public interface Nameable {
private String name;
public String getName() {
return name;
}
public void String setName(String name) {
this.name = name;
}
}

You see? Nothing weird at the first look.
To use it, one would need to do the following:

public class Person implements Nameable {
public Person(String name) {
setName(name);
}
}

Again, nothing weird. All easy and nice. Of course, not for the javac compliler team, as they would need to do some hard work to implement it.

The basic idea for implementation would be the following - use a combination of an interface and anonymous inner class + delegation. So, in practice, the code generated by javac under the hood could be similar to this:

public interface Nameable {
public void getName();
public String setName();
}

public class Person implements Nameable {
// anonymous inner class part of a dirty trick
private Nameable __dirtyTrick = new Nameable() {
private String name;
public String getName() {
return name;
}
public void String setName(String name) {
this.name = name;
}
}
// delegation part of a dirty trick
public String getName() {
return __dirtyTrick.getName();
}
public void String setName(String name) {
__dirtyTrick.setName(name);
}
// normal code
public Person(String name) {
setName(name);
}
}


The hard part left to analyze is to figure out how to resolve "multiple inheritance"-like conflicts, communication of a mixin with a native class and all edge cases and consequences of this. But on the first sight, the idea seems to be workable to me.

Of course, these mixins are not dynamic as in Ruby - so you cannot inject or remove them from a class in runtime. But this would conflict a lot with static type checking, so we need to remember in what environment we are. For me, this is not a big problem.

Tuesday, November 14, 2006

Ruby and samurai swords are for samurais

This little post is a nice proof to my private hypothesis:

Ruby and other samurai tools are best for samurais only.

Let's see what has happened there. Someone has created a 6-line method. Then, as you can see from comments, this method contained 3 severe errors and none of them get detected by the compiler. ;)

It can happen for any language. But I particularly like the beginning of the post:

A coworker who shall remain nameless had this method missing implementation in a module that got mixed into the app helper. This tricked me up for longer then it should, mostly because I hadn't synced up in awhile and so assumed the problem was in changes I made.
Nice thing about that story is that they have had enough tests in a test suite to detect that early. So possibly they are samurais. ;)

But to sum up - I believe that Ruby could be very nice tool for projects with up to 3-5 highly skilled people. If you start to do Ruby projects withbig team of average juniors - beware.

Wednesday, October 18, 2006

More about Java and webcontinuations - Jetty style

There have been some discussion some time ago about continuation model for the web, Java continuations etc. Some were against, some defended continuations, but on the other hand contrasted it with AJAX.

Actually, it seems that Jetty guys found another interesting use of continuations in the Java world. It's main usage is to decrease resource usage when handling AJAX requests, but can be also used for increasing quality of service for the servlet container.

I still did not analyze thing in the details, but it looks interesting. For sure, these are not true continuations as Java does not have them... But it seems to be surprisingly useful example, and also one showing that AJAX and continuations could somehow become friends. Some even believe that REST should joing the gang...

Tuesday, October 17, 2006

What I dislike about Ruby... (part I finished)

Mmmmkay. For you, impatient - mystery resolved.

The line #12 has been an offending one:

self.children.inject do |sum, child|


In fact it should look the following:

self.children.inject(0) do |sum, child|


Do you see the difference? Again, as in the very first example a problem with this little frisky '0'.

Could you easily deduce that from the following error message:

c:/ruby/lib/ruby/1.8/pathname.rb:189:
in `dup': can't dup Fixnum (TypeError)


Here's the point. If you are new to Ruby, you just don't know what's happening.

To summarize. I am not saying I do not like Ruby as a language. I like it quite a lot, it is nice and brings many good ideas, as mixins for example. But let us all face the fact that each technology has its bright face and a Mr. Hyde one.

What I dislike about Ruby... (part I continued)

In a previous post I complained a little bit about Ruby stack traces not being too readable for a mere Java mortals like myself. I got some criticism for my artificial example not being Ruby-ish enough.

Point taken. I am only a mere Java mortal, and not a Ruby superhero. That's exactly why I do expect Ruby stack traces to be a little more readable in the first place. ;)

But after saying "mea culpa", I tried to run one of the "100% Rubyish" examples got in the comments to the last post:

require 'pathname'

class Pathname
def size_without_images
return 0 unless self.exist?
if self.file?
pictExts = %w[ .gif .png .jpg .jpeg .bmp ]
myExt = File.extname(self.to_s).downcase
return 0 if pictExts.include? myExt
File.size self
else
self.children.inject do |sum, child|
sum + child.size_without_images
end
end
end
end

synergy = Pathname.new("c:\\tmp\\synergy")
puts "Size: #{synergy.size_without_images}"


The result was the following:

c:/ruby/lib/ruby/1.8/pathname.rb:189:
in `dup': can't dup Fixnum (TypeError)
from c:/ruby/lib/ruby/1.8/pathname.rb:189:in `initialize'
from c:/ruby/lib/ruby/1.8/pathname.rb:434:in `new'
from c:/ruby/lib/ruby/1.8/pathname.rb:434:in `+'
from test.rb:13:in `size_without_images'
from test.rb:12:in `inject'
from test.rb:12:in `each'
from test.rb:12:in `inject'
from test.rb:12:in `size_without_images'
from test.rb:13:in `size_without_images'
from test.rb:12:in `inject'
from test.rb:12:in `each'
from test.rb:12:in `inject'
from test.rb:12:in `size_without_images'
from test.rb:20


Eeee... Well. I think I was not that far from truth saying that readability of Ruby stack traces could be improved... ;)

If you are a mere Java mortal like me, ask your boss a bonus when you immediately understand why this exception happened in this context. ;)

Friday, October 13, 2006

Smalltalk doesn't suck ... ;)

This little post made me laugh. Especially this sentence:
The results seem to confirm conventional wisdom: Perl sucks the most, Ruby sucks least and all other languages fall somewhere in between.
So, I tried to type that:
Smalltalk sucks
200 results. Definitive proof that Smalltalk is THE language. ;)

Thursday, October 12, 2006

4th wedding anniversary

Happened a week ago, celebrated recently. In a nice place, with good food and this:

I just love great wine.

And I love my wife even much more. ;)

What I dislike about Ruby... (part I)

I will share with you my little frustration. I started to learn Ruby when all this Rails hype was just starting, Rails was in some prerelease version and DHH spent most of his time attacking anything related to Java.

I read the cult pickaxe book and got very attracted to the language. I did not like Rails too much at the time, mostly because of the hype. C'mon, comparing a 4kloc framework having less then a dozen of features with the entire platform is a kind of... childish. So this artificial hype distracted me from my way to Rails, although I played with it and of course it has its niceties.

So again, reading pickaxe I felt - yeah, after killing Smalltalk - this is THE language.

And then... I tried.

Well, what to say... It's nice... But not too friendly. Example?

require 'pathname'

O = "0"
class Pathname
def sizeNoImages()
if not self.exist? then
return 0
elsif self.file? then
case self.to_s
when /.gif$/ then return 0
when /.GIF$/ then return 0
when /.png$/ then return 0
when /.PNG$/ then return 0
when /.jpg$/ then return O
when /.JPG$/ then return 0
when /.jpeg$/ then return 0
when /.bmp$/ then return 0
when /.BMP$/ then return 0
else return File.size(self)
end
else
size = 0
self.children.each do |child|
size = size + child.sizeNoImages()
end
return size
end
end
end

synergy = Pathname.new("c:\\tmp\\synergy")
puts "Size: " + synergy.sizeNoImages().to_s


Do you see the problem? No? So let's try to run it:

test.rb:24:in `+': 
String can't be coerced into Fixnum (TypeError)
from test.rb:24:in `sizeNoImages'
from test.rb:24:in `each'
from test.rb:24:in `sizeNoImages'
from test.rb:24:in `sizeNoImages'
from test.rb:24:in `each'
from test.rb:24:in `sizeNoImages'
from test.rb:24:in `sizeNoImages'
from test.rb:24:in `each'
from test.rb:24:in `sizeNoImages'
from test.rb:32


Do you see the problem now? It is in the line 14:

                when /.jpg$/ then return O


There is a letter O instead of our ol' arabic 0.

I know this particular problem is artificial. But it exemplifies one thing faced pretty often on my Ruby adventures. The error messages you get are somehow similar to Java stack traces, but they are in fact much less precise. I do not even say that with Java analogous code would not compile due to strong type checking. More important point is that even if it compiles, error reports are much closer to the actual buggy place than in Ruby.

Well... of course assuming that you're not working with dumb asses who quietly swallow exceptions... But that's another story.

Wednesday, October 11, 2006

Java and webcontinuations...

For many months now, I have been attracted by the buzz around so called "webcontinuations". However, my daily work with archaic technologies that do not integrate too well with all new fancy toys did not bring too many opportunities to take a look on the buzzy topic

And then I took the challenge. One of advantages of my corporate employer is that there is some space left for personal and team development. This space is shaped in so called "team seminars". The goal is to present some shiny new technology each week to avoid being killed by boredom and frustration.

So my challenge was to present the mysterious "webcontinuations" concept to honourable audience consisting of my colleagues.

I learned two things.

First, I reminded myself how fun Smalltalk is. It was my first love in the world of programming languages, and it will always be. First kisses with blocks... Hot breath of become: on my neck...
As with many things, Smalltalk was the first to leverage power of continuations for the web.

I won't write here neither what the continuation is nor how elegantlySeaside programming model have been designed. Check it out by yourself.

What I will write about is an attempt to provide this programming model to the Java world. The man with a RIFE has dared to do so...

And indeed, the call/answer model has been implemented as in Seaside, plus additional pause() method which exists transparently in Seaside's send-response-handle-request loop. Please take a look at the example from RIFE site:

public void processElement() {
int total = 0;
while (total %lt; 50) {
print(getHtmlTemplate("form"));
pause();
total += getParameterInt("answer", 0);
}
print("got a total of "+total);
}


For you, who are to lazy to click and read the links of this blog - this piece of code will print a form, then pass response to user and wait for request from her browser. After that pause(), the code will wake up as it would never sleep and smoothlessly continue, as there were no HTTP communication in the middle at all.

I knew, as every child on that planet, that Java does not support continuations. So how that was done?

The answer was disappointing.

The class with this magic needs to be instrumented first, using custom classloader and esoteric tools. This is somehow invasive process, and don't look at the RIFE classloader code if you want to remain sane. In input/output terms, it works more or less the following.

Innocent input:

public void processElement() throws EngineException {
String s = "test";
pause();
System.out.println(s);
}


Life-threatening output:

public void processElement() throws EngineException {
ContinuationContext continuationcontext =
ContinuationContext.createOrResetContext();
String s;
switch (continuationcontext.getLabel()) {
default:
String s1 = "test";
continuationcontext.getLocalVars()
.storeReference(1, s1);
TestClass _tmp = this;
continuationcontext.setLabel(0);
throw new PauseException(continuationcontext);
case 0:
s = (String)continuationcontext
.getLocalVars().getReference(1);
break;
}
System.out.println(s);
continuationcontext.remove();
}


I do not know how do you feel now, but I was kind of... disappointed. Marines-heavy machinery plus dodgy exceptions instead of elegant language construct.

I still keep my respect for the heroes who made it actually work... But on the other hand, for me it is an obvious proof that Java in all its nicety is missing a point in some areas. And it will never be fixed.

I really like Java, I do. I understand the reasoning on why not to add continuations to the language. But sometimes I just cannot help myself and not regret the fact that my dreamworld is different than the real one...

Java and webcontinuations then? ... No, thanks, not for me.

Let's check something else. And let me enjoy the fact that my first love has been appreciated by people that count. :)