Paid By the Keystroke?

September 24, 2003 12:54 AM

On Monday evening, I did a bit of Ruby hacking. On Tuesday morning, I arrived at work and my first task involved iterating through a list, and doing something to each of its elements. My fingers were already typing list.each, and I had to wrench my brain from my Ruby mindset back to the Java Way.

Some time later in the day, I read Philip Greenspun's much-linked Java-is-an-SUV flame.

Problem: I have a list of objects. I want to create another list containing the ‘id’ property of those objects.

Solutions:1

Ruby
list.map { |i| i.id }
Perl
map { $_->id } @list;
Python
[x.id for x in list]
Common Lisp (Corrected by Andreas)
(mapcar #'id list)
Smalltalk (from James)
list collect: [:each | each id]
OGNL (from Jason)
list.{id}
Java
List ids = new ArrayList();
for (Iterator i = list.iterator(); i.hasNext(); ) {
    ids.add(new Long(((Thingy)i.next()).getId()));
}
Java w/ 1.5-style Generics/For Loop/Autoboxing
List<Long> ids = new ArrayList<Long>();
for (Thingy x :list) ids.add(x.getId());
Java w/ Commons-Collections (from Chris)
Collection ids = CollectionUtils.collect(
     x, new Transformer() {
            public Object transform( Object thingy ) {
                return ((Thingy)thingy).getId();
            }
        });

1 I was too lazy to test that they work, but the syntax is close enough. Bug reports to /dev/null.

2 TrackBacks

Listed below are links to blogs that reference this entry: Paid By the Keystroke?.

TrackBack URL for this entry: http://fishbowl.pastiche.org/mt-tb.cgi/370

Greenspun redux from Ted Leung on the air on September 24, 2003 8:44 AM

Unsurprisingly, there's been some link traffic generated from Greenspun's Java is the SUV... posting. I've see blog postings, and a thread in the SeaJUG mailing list, and the ultimate signal of success, and entry on the Bileblog. I've no problem Read More

Trackback Testing Page from Confluence: Test Space on June 8, 2004 1:02 AM

This is a link to a JIRA test issue:http://jira.atlassian.com/browse/TST2http://fishbowl.pastiche.org/2003/09/24/paidbythekeystroke Read More

13 Comments

And with Generics, "ForEach" Loop and autoboxing you'd have:
List ids = new ArrayList();
for (Thingy x :list)
  ids.add(x.getId());

For readability sake (meaning, I can look at the code and see what it is doing), I'd pick Java, followed (not so closely) by Perl. Of course, this may reflect the fact that I am not familiar with the other languages....

In OGNL:

list.{id}

Python's list comprehensions rock, there is no doubt about it.

Since Java has so many libraries (like commons-collections) TMTOWDI (apologies for formatting):

Collection ids = CollectionUtils.collect(
x, new Transformer() {
public Object transform( Object thingy ) {
return ((Thingy)thingy).getId();
}
} );

BTW, I think it's important to remember that judging readability is fairly worthless if you don't know the languages involved: 'map' is a common Perl idiom which, if you knew Perl, you'd certainly know. I'd hazard a guess that most of us don't maintain code in a language we don't know :-)

The Common Lisp code portion can even be shorter (and less irritatingly lambda-ridden (-:):

(mapcar #'id list)

The conclusions I draw:

#1: bring on 1.5!
#2: (obviously) the one you know is easiest to understand.

Personally the 1.5 example seems to read easier than all except the Smalltalk and maybe the Python examples. But I'm biased of course, as per #2.

With F-Script:

list id

In C++, assuming that 'mylist' is the list you are working on, and the elements are instances of 'myobj':

list<long> ids;
for (list<myobj>::const_iterator it = mylist.begin(); it != mylist.end(); ++ it)
    ids.push_back(it->id);

Or if it's a list of pointers to instances of myobj:

list<long> ids;
for (list<myobj*>::const_iterator it = mylist.begin(); it != mylist.end(); ++ it)
    ids.push_back((*it)->id);

It's hardly fair to compare statically-typed Java with a bunch of dynamically-typed languages. So how about adding a haskell version:

map thingy_id list

The only "fair" comparison here is with C++. Java was designed to be a better C++, and it is.

list.map( Thingy each => { return each.id; } );

Nice (statically-checked, JVM bytecodes, uses Java libraries) http://nice.sourceforge.net/index.html

In the Python example, 'list' need not actually be a materialised list but can be any iterable, so allowing the source items to be obtained lazily; with appropriate type declarations, the same could be true of the various Java examples. Nevertheless what is *produced* by the Python and Java versions given here will still be a materialised list. Python 2.4 will introduce generator expressions, which combine the ideas of generators and list comprehensions, so allowing the transformation of one iterable into another without materialising a list:

(x.id for x in list)

I imagine that the Java equivalent of this would be even longer than the examples given before.

Previously: Music Consumption

Next: Introducing: Dysfunctional Programming