I am a software engineer at Google on the Android project and the creator of the Java testing framework TestNG. When I'm not updating this weblog with various software-related posts or speaking at conferences, I am busy snowboarding, playing squash, tennis, golf or volleyball or scuba diving. Cedric is a DZone MVB and is not an employee of DZone and has posted 90 posts at DZone. You can read more from them at their website. View Full User Profile

Open type systems

05.12.2011
| 3443 views |
  • submit to reddit

java.lang.Class is probably one of Java’s most famous classes, and whether you write applications or frameworks, you have probably encountered it many times, either superficially (getClass()) or in more depth (reflection, class loaders, etc…).

java.lang.Class is also a very special class in the Java ecosystem, and as such, it is limited in some very specific ways. One of them is that developers can’t create a new Class object themselves (the class has no public constructor), only the JVM can create Class objects. When you are writing Java code and you want to materialize some of these objects, your options are fairly limited:

  • Create a class loader and use the defineClass() method. Class loaders are complex and require a lot of intimate knowledge of the JVM to get right, and defineClass() also requires you to supply the bytecode for the class you want to create.
  • Code generation. This is the more traditional approach. It’s easier to achieve in some ways (all you need to do is generate the source of the class you need) and more complicated in others (you need to infect your build with the knowledge of these generated classes and teach it how to bundle them with your application).
  • You can use dynamic proxies. Dynamic proxies don’t exactly materialize new classes, so they shouldn’t really be part of this list, but I thought I’d mention them since they can be a pretty powerful solution to the overall problem of generating new types in Java programs (note that this approach is less typed than the other two).

Despite their shortcomings, all these approaches have been used with great success by various Java frameworks, and these techniques played a great role in making Java such a strong platform that remains able to solve most of the engineering problems that arise these days.

Having said that, what can we do to improve on these approaches?

Imagine a new type called IType. This is actually an interface, so any class can implement it. Let’s now assume that everywhere in the JVM where a Class is expected, we can use an IType instead (obviously, we’ll make Class implement IType). IType is the new representation of a class inside the JVM, and any object that implements it can be passed instead of a Class.

Obviously, an IType needs to be able to perform all the operations that Class can, among which:

  • Return information about its name, package, parent type(s), nested types, etc…
  • Respond to standard introspection operations, such as returning the list of methods that it exposes.

Obviously, the methods returned by the IType need to be abstracted as well, so instead of returning java.lang.reflect.Method, we return a new type called IMethod. We place the same requirements on IMethod that exist on Method: introspection much work on these objects and, more importantly, we need to implement invoke(). If the object we are returning is an instance of Method, implementing invoke() is trivial (just delegate it to the underlying Method object).

But what happens if, instead of returning standard Java Class and Method objects, we decide to return something different?

Actually, what could these other objects be?

As it turns out, anything. They could represent files: .xml obviously, but how about .xsd or .properties? Or how about sources of another language? Maybe a .groovy, .bash or .scala? Thinking further outside the box, how about concepts that are not files, such as database tables? Or virtual files, or files present on a remote file system? How about the endpoint of a network connection (and we don’t care what’s feeding this endpoint)? We could also decide to represent the results of a REST or AJAX or JSON API.

This new type system doesn’t care what the underlying concept actually is, all it needs is a set of ITypes (and a few other details that I’m glossing over), and it will expose these types to the JVM as if they were genuine classes. Whether they are backed by Java bytecode or some other logic is irrelevant.

Here is a quick example of what such a type might look like.

Let’s suppose we want to make Java property files first class citizens in this new type system (it’s a silly example since a simple hash table is good enough, but this is just for illustration). The idea is that whenever we encounter a file called “foo.properties”, we’ll create a class called FooProperties and each key/value found in this file will be represented as a getter. For example, loading this file in this new type system:

# File: host.properties
host: 127.0.1.0
port: 1245

will allow you to write the following code:

HostProperties fp = PropertyTypeLoader.load("host.properties");
System.out.println("Host:" + fp.getHost() + " port:" + fp.getPort());

The implementation of the corresponding IType and IMethod interfaces is pretty straightforward in this case, but this should give you an idea of the flexibility of such a type system.

What I have just described is basically Gosu’s Open Type System. Gosu is not just “yet another JVM language”, it also enables the kind of type openness that allows you to materialize pretty much anything as a real Gosu type. Once you have described your type, it becomes a part of your Gosu program and as such, benefits from the same privileges as any other type (e.g. it can be used by IDE’s for completion, browsing, refactoring, etc…).

Having said that, let’s now put things in perspective:

  • Java’s metaclass design is intentional: it was conceived this way for security reasons, the idea being that types materializing in your JVM process need to go through a very specific pipeline so it can be validated and checked against malignant attacks. I am guessing that this system is extremely paranoid because Java was initially driven by applets, but I wonder if such concerns are still valid today.
  • While elegant, Gosu’s open type system is basically just saving you from a code generation phase.

I’m guessing that not everyone will think that the benefits from such a type system outweigh the drawbacks, but I’d love to hear some feedback on whether you think that future languages should give access to such functionality or if it’s just a nice theoretical toy whose practicaly is doubtful.

Here is some additional material on Gosu’s Open type System:

 

From http://beust.com/weblog/2011/05/10/open-type-systems/

Published at DZone with permission of Cedric Beust, author and DZone MVB.

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

Tags:

Comments

Alex(JAlexoid) ... replied on Sat, 2011/05/14 - 1:42am

IType

Where is this "I" prefixing of interfaces come from C++? Pascal?

Why do people still use it, when all of the core Java, most books, most(if not all) frameworks use Suns naming guidelines - interfaces are not prefixed. Android also does not use "I" prefixes for interfaces.

Carlos Hoces replied on Sat, 2011/05/14 - 8:30am

As I can see, IType is just a name for a class. I do not see any prefix on it.

I began to use a "suffix" for interfaces to better identify them while browsing projects, as 

public interface TablesFace{}

public class Tables implements TablesFace{}

It helps me to quickly realize it's an interface, without opening the file, while browsing. Moreover, actual use inside code, helps to see who's the interface and who's the implementation.

Neil Crow replied on Sat, 2011/05/14 - 1:58pm in response to: Alex(JAlexoid) Panzin

Hungary ... Its a form of Hungarian notation. It could be argued that in modern IDE's like Eclipse / NetBeans / IntelliJ etc. it is no longer necessary, as you will often get mini-javadoc info if you just hover your cursor ofver a type or a variable. However if you are coding in a text editor like vi or notepad++, the type hints prefixed onto the name could still be useful.

Comment viewing options

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