Lists. Java vs Python.

1 AM May 16, 2006

Java


public List getImageItems() {
    List result = new ArrayList();
    for (Iterator iter = items.iterator(); iter.hasNext();) {
        ReportItem item = (ReportItem) iter.next();
        if (item instanceof ReportImageItem) {
            result.add(item);
         }
     }
    return result;
}

Python:


@property
def imageItems(self):
    return [i for i in self.items if isinstance(i, ReportImageItem)]

I’m just saying. And, no, I’m not putting this on Javablogs.

By alang | # | Comments (15)
(Posted to Python, Java and Rants)

Comments

At 02:49, 16 May 2006 Jed Wesley-Smith wrote:

Well, there are ways to make the java code more generically useful, and simpler.

Consider the interface:

    public interface Filter<T>
    {
        boolean accept(T obj);
    }

and the implementation:

    public class InstanceofFilter<T> implements Filter
    {
        private final Class<? extends T> clazz;
    
        public InstanceofFilter(Class<? extends T> clazz)
        {
            this.clazz = clazz;
        }
    
        public boolean accept(Object obj)
        {
            return (obj == null) 
                ? false 
                : clazz.isAssignableFrom(obj.getClass());
        }
    }

along with the handy util method:

    public static class FilterUtil
    {
        public static <T> List<T> filter
        (
            Collection<T> collection, 
            Filter filter
        )
        {
            List<T> result = new ArrayList<T>();
            for (T t : collection)
            {
                if (filter.accept(t))
                    result.add(t);
            }
            return result;
        }
    }

Now you can simply call:

    public List getImageItems() {
        return FilterUtil.filter(
            items, 
            new InstanceofFilter<ReportItems>(
                ReportImageItems.class
            )
        );
    }

Which is a one liner formatted for a narrow blog ;-)

I admit I used Java5 (just cause I can), but the degenerified (and foreached) version is just as useful. There are obviously some additional implementation tweaks you would probably add, like passing in the result list so you can swap the List implementation etc. but you get the idea...

(btw. have you considered using tab as well as space for your source indenting?)

(#)
At 03:10, 16 May 2006 Daniel Sheppard wrote:

Because I like to stir:

<pre>
  def image_items
    items.select {|i| ReportImageItem === i}
</pre>

I'm just saying...

(#)
At 04:36, 16 May 2006 Alan Green wrote:

Jed: thanks for showing how Java makes simple things simple.

Daniel: yes, I'll settle for that (edit... did you mean something like?)

  def image_items
      items.select {|i| ReportImageItem === i.class}
(#)
At 06:26, 16 May 2006 Jed Wesley-Smith wrote:

hehe! well the scaffolding is a bit complex, but the actual final usage isn't that bad. You might get it for nothing in python, but hey, you lose static typing ;-)

(#)
At 08:00, 16 May 2006 Daniel Sheppard wrote:

No,

  ClassName === object 

is the ruby equivalent of java's

  object instanceof ClassName

I did leave off the "end" to match with that def though. Ruby has made me want to do a lot of stuff like what Jed has done in ruby - I miss my blocks when I have to go back.

(#)
At 13:44, 16 May 2006 steven_h wrote:

"You might get it for nothing in python, but hey, you lose static typing ;-)"

In Haskell:

 imageItems = [i | i <- items, isReportImageItem i]
     where isReportImageItem item =
              case item of ReportImageItem _ -> True; _ -> False

put that into your static typing pipe and smoke it :)

(#)
At 16:26, 16 May 2006 Michael Chermside wrote:

This is actually the most interesting language shootout I've seen in a while. It's an incredibly simple task, the kind of thing that takes up only about "1/2 a line of code" in my brain. The Java 1.4 version is unbelievably verbose (well, if I didn't code in it all day I'd have trouble believing it). But the Haskell, and Python versions are still just a little too long for comfort. The Ruby version seems nicest. (And I say that as a Python programmer who doesn't much like Ruby.)

One sign of good language design: simple things can be stated simply.

(#)
At 18:42, 16 May 2006 Juha Komulainen wrote:

The Haskell version above is a bit wordy since it defines the predicate in addition to the list comprehension. Since Haskell doesn't have classes in the same sense as other languages mentioned here, a direct comparison is not meaningful. If we pretend that Haskell would have classes and "instanceOf cl obj" function for checking if object is an instance of a class, you'd say:

  imageItems items = [i | i <- items, instanceOf ImageItem i]

or more idiomatically:

  imageItems = filter (instanceOf ImageItem)

This, of course, is statically typed and works for an infinite list of items.

You gotta love Haskell. :)

(#)
At 23:53, 16 May 2006 Alan Green wrote:

Jed: "the actual final usage isn't that bad". Dude! Can I have some of your drugs? Sounds like just the thing for making all my Java list manipulation code seem ... elegant.

(#)
At 14:10, 19 May 2006 Richard wrote:

That Java 5 code could become prettier if it:
a) had another factory method for the InstanceofFilter, and
b) FilterUtil.filter() took a Iterable<A>, rather than a Collection<A> as its arg.

    public class InstanceofFilter<T> implements Filter
    {
        public static <T> InstanceofFilter<T> create(
            Class<T> clazz)
        {
            return new InstanceofFilter<T>(clazz);
        }
        ...
    }
    public class FilterUtil
    {
        public static <T> List<T> filter(
            Iterable<T> in,
            Filter filter)
        {
            ....
        }
    }

That final code becomes:

    public List<ReportItem> getImageItems()
    {
        return FilterUtil.filter(
            items,
            InstanceofFilter.create(
                ReportImageItem.class));
    }

I said prettier, but I'm not going to call it pretty just yet. And anyway, the type constraint on the returned value is too weak!

(#)
At 14:36, 19 May 2006 Richard wrote:

Better would be something like the following:

    public List<ReportImageItem> getImageItems()
    {
        return FilterUtil.filterType(
            items,
            InstanceofFilter.create(
                ReportImageItem.class));
    }

where the new filterType method looks like the following:

    public <S,T> List<T> filterType(
        Iterable<S> in,
        TypeFilter<T> filter)
    {
        List<T> out = new ArrayList<T>();
        for (S source : in)
        {
            if (filter.accept(source))
            {
                out.add(filter.transform(source));
            }
        }
    }

InstanceofFilter gains the following:

    public class InstanceofFilter<T> implements TypeFilter<T>
    {
        ....
        T transform(Object o)
        {
            return clazz.cast(o);
        }
    }

Finally, TypeFilter is defined as:

    public interface TypeFilter<T> extends Filter
    {
        T transform(Object o);
    }

Fact is, even my best Java 5 version is still far more verbose than the Python, Haskell or Ruby versions above. Most of this verbosity comes from specifying the return type, the class containing the filters and creating the filter itself. These just seem to be the sunk costs of the Java Way. sigh.

At least I can look forward to a day in the not too distant future when Java will have all the utils needed for this that support generics, rather than everyone rolling there own. Even if it turns out like the STL algorithms, that's still a vast improvement on the release version libraries available for Java from Jakarta. It will be interesting to see which Java 5 port (mentioned elsewhere on this blog) 'makes it'.

(#)
At 05:33, 22 May 2006 Jed Wesley-Smith wrote:

Richard, I'll pay that, much prettier. Maybe we should create our own Generified Collections Util and post 'em all here ... don't think Alan will mind all that much!

(#)
At 23:57, 24 May 2006 Isaac Gouy wrote:

"I'm just saying."

Yes but what are you just saying? And why not say it with Java 5:

 public List<ReportItem> getImageItems() {
   List<ReportItem> result = new ArrayList<ReportItem>();
   for (ReportItem i : items)
      if (i instanceof ReportImageItem) result.add(i);
   return result;
 }

Are you just saying that Java is more verbose, or are you saying why Java is more verbose?

Maybe you're just saying Java currently doesn't provide a rich list api, and there wouldn't be any significant problem adding generic library methods like map and filter. Even with library methods, using that anonymous class style is goingto be verbose:

 public List<ReportItem> getImageItems() {
   return Lists.filter(items,
     new Filter<ReportItem>() {
       public boolean accept(ReportItem i){
         return i instanceof ReportImageItem; }
     });
 }

And there are still problems, you'll have noticed that the code snippets hardcode the collection return type

 List<T> result = new ArrayList<T>();

We'd really like a straightforward way to create an empty collection of the same type as the Lists.filter collection argument, and declare Lists.filter to have that same return type. I don't know how to do that in Java.

There already is a filter method in another JVM language - Nice - which operates on ArrayList, LinkedList, HashSet, Stack etc. Here's the signature

 <Collection C, T, U | T <: U>
    C<U> filter(C<T>, T->boolean);

So in Nice we could write

 List<ReportItem> getImageItems() =
  items.filter(ReportItem i => i instanceof ReportImageItem);
(#)
At 06:52, 25 May 2006 Isaac Gouy wrote:

That isn't how it previewed :(

(#)
At 17:57, 25 May 2006 Isaac Gouy wrote:

C# 3.0

 IEnumerable<ReportItem> ImageItems(){
    return items.Where(i => i is ReportImageItem); }
(#)

Add Comment




(Not displayed)






(Leave blank line between paragraphs. URLs converted to links. HTML stripped. Indented source code will be formatted with <pre> tags.)




© 2003-2006 Alan Green