Collin Fagan is a Sr. Software Engineer at NAVTEQ working on next generation map building software. He holds a BS in Computer Science from the Rochester Institute of Technology. Collin has worked in the Map, Medical, Produce Warehousing and Telecommunications industries on a wide assortment of projects ranging from customized Linux thin clients to highly concurrent telecommunications control systems. Collin has posted 13 posts at DZone. View Full User Profile

Experimenting with First Class Methods (FCM)

03.08.2008
| 8033 views |
  • submit to reddit

Stephen Colebourne has a prototype implementation of the FCM closures proposal. I took some time to download and play with the new syntax and functionality.

I tried to focus on some of the functionality FCM provides that other closure proposals do not. Namely method and field literals. I think FCM can help create flexible models for swing components. In the past I've done this using plain reflection but FCM makes things easier.

This is a screenshot of the demo application.

It displays three lists and one table all of which are backed by the same collection of SuperHero beans.


I found that I could apply FCM in one of the first few lines of my demo.

SwingUtilities.invokeLater(#startApp());

This calls my startApp() method on the event dispatch thread. I have to admit that while I'm not a fan of in-lining this was preferable to the traditional method of building a Runnable and passing that to invokeLater

Here is a very basic ListModel that can expose any public field of an object.

/**
* Wraps a list of elements and exposes one field to the list model
* interface
*
* @param <E>
*/
private class FCMFieldListModel<T> extends AbstractListModel {

private List<T> backingList;
private Field targetField;

public FCMFieldListModel(List<T> data, Field target) {
backingList = data;
targetField = target;
}

@Override
public Object getElementAt(int index) {
try {
return targetField.get(backingList.get(index));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}

@Override
public int getSize() {
return backingList.size();
}

}

In my case I'm building a list of superheroes and wish to expose the last name field.

FCMFieldListModel<SuperHero> lastListModel = new FCMFieldListModel<SuperHero>(heroes, SuperHero#lastName);

The last parameter is the new field literal syntax from FCM. It allows me a type safe way of specifying which field I want to expose.

To create more list models that expose other fields I just need to create another FCMFieldListModel and expose a different field.

FCMFieldListModel<SuperHero> listModel = new FCMFieldListModel<SuperHero>(heroes, SuperHero#firstName);

Now most of the time a bean will not expose a field. Instead getter/setter methods are used to expose this information. FCM has method literals as well as field literals. The code for a FCMMethodListModel is very much like FCMFieldListModel but it takes a Method reference instead of a field refrence.

       /**
* Wraps a list of elements and exposes one method to the list model
* interface
*
* @param <E>
*/
private class FCMMethodListModel<E> extends AbstractListModel {

private List<E> backingList;
private Method targetMethod;

public FCMMethodListModel(List<E> data, Method target) {
backingList = data;
targetMethod = target;
}

@Override
public Object getElementAt(int index) {
try {
Object item = backingList.get(index);
return targetMethod.invoke(item);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}

@Override
public int getSize() {
return backingList.size();
}

}

Basically this lets you tell the list model which method of your bean to call to represent your bean in the list. It is used much like the FCMFieldListModel model.

FCMMethodListModel<SuperHero> fullListModel = new FCMMethodListModel<SuperHero>(heroes, SuperHero#getFullName());

Finally I used this same technique to build a table model.

FCMTableModel<SuperHero> superTableModel = new FCMTableModel<SuperHero>(heroes,
SuperHero#getFirstName(), SuperHero#getLastName(),
SuperHero#getHeroName(), SuperHero#getFirstAppearance());

The constructor takes a list of SuperHeroes and a variable list of methods to use as columns. This code is all it takes to populate the table seen in the center of the screenshot.

The first appearance column of the super hero table is a date without a day. I decided to use an anonymous inner method to implement a cellrendrer to format the date.

TableColumn dateColumn = superHeroTable.getColumn(SuperHero#getFirstAppearance().getName());

// in-line cell renderer for the date column of the superhero table
dateColumn.setCellRenderer(#(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column){
if(isSelected){
dateRenderer.setBackground(UIManager.getColor("Table.selectionBackground"));
}else{
dateRenderer.setBackground(UIManager.getColor("Table.background"));
}
dateRenderer.setText(sdfDateColumn.format((Date) value));
return dateRenderer;
});

Overall I have to say I like FCM. Even in it's incomplete state I feel it's still a step forward. The method and field literals were very convenient and useful. I can see myself creating generalized adapter classes around this functionality. As I said before I'm not a fan of in-lining code. I tend not to in-line inner classes either. But the anonymous inner method syntax seemed straight forward enough. Also I much prefer using the # syntax to pass method to invokeLater.

My examples involved a bean and it's associated methods. Yet there is no way currently to specify that a method used as a parameter come from any specific class. It certainly would be an error to pass a FCMMethodListModel System.out#println(Object). I think this is one of the items on the list of things to do for FCM but I'm not certain.

I've made the source code for this demo available on google docs. Just remember that you need the prototype FCM implementation to run it.

Finally I'd just like to thank Stephen for all his hard work in creating this prototype. It's been fun to experiment with it.

Note:
This is demo level code. It was written to play around with FCM and a such the models are not as robust as they could be. Their job is to adapt an unchanging list of beans using FCMs method literals. I will probably revisit FCMTableModel at some point to show how it could be enhanced. As it stands now they have no support for events. Also I'm not sure a cell renderer was a good choice for an anonymous inner method example. If you read the javadoc for DefaultTableCellRenderer it talks about overriding some of the JLabel methods for performance reasons.

 

AttachmentSize
fcmDemo.png26.85 KB
Published at DZone with permission of its author, Collin Fagan.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

cowwoc replied on Sun, 2008/03/09 - 1:28am

The problem with tools which automate CRUD creation is that they produce really bad APIs. We've spent so much time trying to come up with better CRUD automation tools that we haven't stopped to consider whether we're going in the right direction to begin with.

JavaBeans and XML enable computers to parse data programmatically but they amount to really awful API design and configuration file formats. In short, they're made for computers, not humans. Fix that problem first and all the rest will follow.

 

Resources:

http://martinfowler.com/bliki/GetterEradicator.html

http://www.javadonkey.com/blog/are-getters-and-setters-evil/

Collin Fagan replied on Mon, 2008/03/10 - 10:23am in response to: cowwoc

I'm sorry I am having trouble seeing the relevance of your statements. I used references to getters and setters because that what most people see in the wild. You can have a reference to any method, regardless of it's name and the above code would work fine. I think this actually makes things less complex because you would have to write table/list/tree models less often. Do you have an issue with type-safe method references?

Charlie Hubbard replied on Mon, 2008/03/10 - 1:47pm

 

Thank you Collin for putting together this review. I know you didn't pick the name of the proposal so this isn't directed at you. But this is NOT closures. It's really just passing Method objects around, which is something we can already do today. Don't get my wrong I'm not against something like this. However, passing references to functions IS NOT closures. It's just adding syntax directly to the Java language which would hopefully make using reflection easier. I mainly say this such that people who don't really understand what a closures are don't confuse this proposal for real closures. Or worse accept this proposal thinking they are getting the full power of closures when they're just getting sold a cheap knock-off.  This is just passing methods as arguments.

I do believe reflection is one of the most under-rated features of the Java language. Without it there would be no way the framework explosion could have happened. Java owes a lot of it's popularity to reflection, and anything we can do to improve it will have huge wins across the platform. One of the reasons more people don't write code this way is because it's cumbersome to use. While this is interesting. It's not yet there so I hope they could improve the syntax both for invoking reflection and getting references to reflective objects (i.e. methods, and fields).

I don't see why we couldn't just use the dot just like we do with functions today. Something like:

Method methood = MyObject.method

That way a method and a field reference don't differ at all in synaxt used. Differentiating methods by parameter types would need some new type of syntax. Possibly looking like generics with:

Method method = MyObject.someMethod<String,int>

Things to consider that could make this stuff more helpful:

1. Using Class to get references vs. an instance to get references to Method objects: One of the biggest problems I have with reflection is that Method objects forget which instance they came from. So lots of times you have to rejoin the Method object with a specific instance you want to invoke that on. What if the method returned from an instance would remember the object it was gotten from. (This would be a specific use of closures in a way, but not in a general sense). Retrieving methods from a class would return just a Method object not associated with an instance like it does today. Consider:

InstanceMethod method = someInstanceObject.method

Object result = method.invoke();

Notice that I didn't have to pass someInstanceObject back to the method's invoke method. It remembered that I got the method from the instance someInstanceObject. Constrast that with a class and you'll see the difference:

 

Method method = MyObject.method;

Object result = method.invoke( someInstanceObject );

 

These two examples are equivalent, but you see how the caller doesn't have to keep track of the instance it came from. This makes it easier to hide contextual data inside an object without have to pass that contextual data through the caller of the method reference. This makes it easier to integrate two objects without having to know details what data method needs. Consider if a comparator is being used to sort a list of items where the comparator has some instance data it needs that isn't apart of the objects it's sorting. Passing just method objects around can't account for that use case.

Also I'd like to see an Object.invoke() method to make using reflection easier. For example:

Object result = someObject.invoke("someMethod", param1, param2 );

One liner method innovcation for reflection. That's a really simple reflection helper, and every object would get it!

Collin Fagan replied on Mon, 2008/03/10 - 2:35pm in response to: Charlie Hubbard

Hi Charlie,

I was exploring just one of the aspects of FCM. I was interested in some of the functionality FCM has that other closure proposals do not. Some of the things you are looking for are possible in FCM. I suggest you look into the bound method references. They "remember" which object they came from.

Stephen Colebourne replied on Tue, 2008/03/11 - 5:42pm in response to: Charlie Hubbard

I know you didn't pick the name of the proposal so this isn't directed at you. But this is NOT closures. It's really just passing Method objects around, which is something we can already do today.

See the Inner Methods part of the FCM proposal for the closure-like part. Method literals (described here) and Method references (also in FCM) are obvious counterparts to closures, and often more useful.

One of the biggest problems I have with reflection is that Method objects forget which instance they came from. So lots of times you have to rejoin the Method object with a specific instance you want to invoke that on.

See bound method references.

I don't see why we couldn't just use the dot just like we do with functions today. Something like:

Method methood = MyObject.method

Because variables and methods are in different namespaces. You can have a variable and a method with the same name. Thus the code above cannot identify which you are referring to.

Also I'd like to see an Object.invoke() method to make using reflection easier. For example:

Object result = someObject.invoke("someMethod", param1, param2 );

Adding methods to Object can affect any current Java program. It is considered to be backwards incompatible as I understand it, and will never happen.

 

Stephen Colebourne replied on Tue, 2008/03/11 - 5:52pm

Collin, for this application, a better approach would be to use Instance Method References. These are implemented in svn, rather than the latest downloadable zip.

public interface DataExtractor {
  Object extractData(Object targetToExtractFrom); 

You can then replace Method with DataExtractor. Now, only the correct methods can be passed in (like SuperHero#getFirstName()) and there is no need for the try/catch in the FCMMethodListModel (because no reflection is being used).

Collin Fagan replied on Tue, 2008/04/08 - 7:34am

Thank you, I'll go check it out.  I am really getting to like FCM.

Ming Shing replied on Thu, 2010/11/25 - 5:11am

This makes it easier to adumbrate contextual abstracts central an article after accept to canyon that contextual abstracts through the addition of the adjustment reference.

pass4sure 000-009, pass4sure 000-005, pass4sure 000-M38

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.