Panasonic Youth rob sanheim writes about software, business, ruby, music, stuff and things



Posted
1 August 2005 @ 12pm

Tagged
Java, Patterns, Ruby

Discuss

Fowler on collections and closures

Martin Fowler blogged on how Ruby deals with collections using blocks (or closures). Its a nice example of some of the power you really miss having in the Java/C# family of languages.

Wouldn't it be nice if instead of this:

JAVA:
  1. List managers = new ArrayList();
  2. for(Iterator iter = employee.iterator(); iter.hasNext();) {
  3.    Employee emp = (Employee) iter.next();
  4.    if(emp.isManager())
  5.        managers.add(emp);
  6. }

You could just do this:

JAVA:
  1. List managers = new ArrayList();
  2. managers.addAll( employee.find{ |e| e.isManager() });

On a related note, is there any difference between a "closure" and a "block" in Ruby?


6 Comments

Posted by
Brian Vaughn
1 August 2005 @ 1pm

Seems like something I would rather do in my database query. Find all employees that are managers.


Posted by
Brian McCallister
1 August 2005 @ 1pm

Pretty close, except that a block isn’t actually a function in and of itself. It can be thought of as an unbound expression rather than a function, which is more accurate. In any sane case it is going to be bound to a Proc object, which is what ruby’s lambda() creates, either explicitely or implicitely via passing it as an argument to a function call ( ie the block in [1,2,3].each {|i| pus i} which uses the convenience syntax for passing blocks instead of an explicit parameter for it:

class Foo
def each(&proc)
proc.call 1
proc.acll 2
end
end

class Bar
def each
yield 1
yield 2
end
end

The two classes conceptually do the same thing, Foo just makes it explicit, Bar makes it implicit. The convenience syntax is really nice when working with functions which are parameterized and take a block — especially if there are default params, named params, or a variable number of params =).

Okay, way more detail than you wanted.


Posted by
Rob
1 August 2005 @ 1pm

Brian V: granted, that is certainly something that might be better done in SQL. It was just an example, and I’m sure you could imagine cases where you can’t or don’t want to do that with a db hit.

Brian M: thanks for the explanation, thats what I was looking for.


Posted by
Tom Hawtin
1 August 2005 @ 2pm

(If my angles get stipped I shall be very annoyed.)

In currrent Java, the first version would be:

List managers = new ArrayList();
for(Employee emp : employees);
if(emp.isManager()) {
managers.add(emp);
}
}

Assuming we want closures and don’t want to throw away static typing. The closure example would come out something like:

List managers = new ArrayList();
managers.addAll(employees.find{ |Employee e| e.isManager() });

If only the Java had a degree of target typing for inner classes the Java could look like:

List managers = new ArrayList();
managers.addAll(employees.find(new () (Employee e) { return e.isManager(); }));

or

List managers = employees.select(
new () (Employee e) { return e.isManager(); }
);

That wouldn’t be so bad, and would take little change to the language.


Posted by
Tom Hawtin
1 August 2005 @ 2pm

(I am very annoyed.)

In currrent Java, the first version would be:

List<Employee> managers = new ArrayList<Employee>();
for(Employee emp : employees);
if(emp.isManager()) {
managers.add(emp);
}
}

Assuming we want closures and don’t want to throw away static typing. The closure example would come out something like:

List<Employee> managers = new ArrayList<Employee>();
managers.addAll(employees.find{ |Employee e| e.isManager() });

If only the Java had a degree of target typing for inner classes the Java could look like:

List<Employee> managers = new ArrayLis<Employee>();
managers.addAll(employees.find(new () (Employee e) { return e.isManager(); }));

or

List<Employee> managers = employees.select(
new () (Employee e) { return e.isManager(); }
);

That wouldn’t be so bad, and would take little change to the language.


Posted by
Tomas
2 August 2005 @ 11am

Python:
def isManager(emp): return emp.isManager()
managers = filter(isManager, employees)
or
managers = filter(lambda emp: emp.isManager(), employees)

Or even simpler:
managers = [emp if emp.isManager() for emp in employees]


Leave a Comment

adventures in daycare Rails tutorial using Eclipse 3.1