9/8/12

Phantom types in Java

Introduction
One of the things that I like about types in programming languages is that they're there to help you (although sometimes feels the opposite). The more things you can check at compile time, the less you need to do during tests (if you need to do it at all!).
One of those techniques are Phantom Types, and although well known in advanced languages (Haskell, Scala, OCaml, etc.) it seems to be relativelly unknown in Java despite the fact it can be perfectly used.

Since Java 1.5, we have parametric types (generics). Once you have that, you can add types parameters to other types...

public class MyTpye <TypeParameter> { .... 

you can have methods with generic parameters

public <T> Result doSomething( MyType<T> p){ 
.... do something with p ... 
}

or require specific type parameters on your methods (called a generic type invocation ).

public Result doSomethingStringy( MyType<String>  p){ 
.... do something with p ... 
}

A ghost in the (type) machine
So, what are phantom types?. Now, normally when you require a specific type in the parameter you use it in the method body (say, when you have sum(List<Integer> xs) you'll use the fact that you have a list of Integers to sum them) , but what happen if you don't? Now you have a parameter type that never appears in the body, although is there, requiring that specific parameter in the type and preventing compilation if doesn't match. That's a phantom type :)

A simple example
Here an example: let's model a plane that can be either flying or landed and a takeOff and land methods that can only be applied to landed and flying planes respectively.
First, let's define the different flight status as marker interfaces:




Now, our plane class parametrized by the flight status:

And finally, our flight controller class with the takeOff and land methods:

The interesting part is in the land and takeOff methods. For example, in the land method, we require a Plane<Flying> but we just return a landing plane, (without using the Flying interface in the body). That's how we enforce that a plane must be flying to be able to land.
What I wanted to show with this is pretty silly example is how you can use phantom types to enforce some rules.

What are they good for?
Ok, now you have a way to require at compile type certain parameter on a type, what can you use it for?
Turns out it you can use to enforce many constraints:
Enforce a particular state: in the previous example, we used phantom types to require a specific state in a method (flying/landing in this case). In the same way we can require a connection to be open when we do a query or close it:

public ResultSet execute( Connection<Open> c, Query q) ....

public void close( Connection<Open> c) ....

(but is not safe, will work a better example)

You can also use it for safer Ids:
Usually Ids are Int or Strings, and is very easy to mix them up, e.g. in buy(String productId, String customerId) you can swap the Ids by mistake and you can get subtle bugs (the productId might match a customerId). With phantom types you can define an Id class parametrized by the entity and you get buy(Id<Product> productId,  Id<Customer>  customerId) and you'll get a compiler error if you pass a product id where you expect a customer id.
The full example  (in Scala):






Go ahead and Type!
As you see, phantom types are pretty straightforward and gives you more expressive power (in particular, will allow you to get more mileage from Java's type system). I hope they get more use in Java...

18 comments:

Unknown said...

Another usage for Phantom types is for creating type safe instance builders. I've written about this some time ago already: https://michid.wordpress.com/2008/08/13/type-safe-builder-pattern-in-java/

Gabriel Claramunt said...

That post was among the original references I found... I've added it to the links.
Thanks a lot!

Edmund Horner said...

public void close( Connection c) ....

So how does `close` change the type of `c` to `Connection` ? ;-)

I guess you could have:

public Connection close(Connection c) ....

Connection c2 = close(c);

With the understanding that `c` no longer exists after the call to `close`. Makes me wonder if there are any imperative languages that support functions that render their arguments unusable. I think Whiley would support something like `c = close(c)` where the type of `c` has changed after that call, though I'm not sure where it's at in terms of generics.

Edmund Horner said...

Damn, all the generic < and > chars have been stripped as HTML. :<

Read it as:

public Connection<Closed> close(Connection<Open> c) ....

Connection<Closed> c2 = close(c);

Anonymous said...

Your approach requires new object to be created in order to "change" the phantom type.

Another interesting approach is typestate (http://dl.acm.org/citation.cfm?id=10693) which allows object to change it's type during its lifetie

Javin Paul said...

Learned new way to use Generics. worth including in my list of advantage of using Generics in Java

Will said...

"well known in advanced languages (Haskell, Scala, OCaml, etc.) "
Why do you call then "advanced" languages?

Gabriel Claramunt said...

I called advanced languages because they have an advanced type system more expressive than the Java one.

Gerard thomas said...
This comment has been removed by the author.
Shawn Michaels said...

Thanks for taking the time to discuss this, I feel strongly about it and love learning more on this topic. If possible, as you gain expertise, would you mind updating your blog with more information? It is extremely helpful for me. BY - software development

Nikos Maravitsas said...

Hi Gabriel ,

Great blog! Is there an email address I can contact you in private?

Fritz Morse said...

Makes wonder if there are any crucial 'languages' that support functions that provide their justifications useless.

jabbar singh said...
This comment has been removed by the author.
Amit Singh said...

what is fantastic post? this is so chock full of useful information I cannot wait to dig deep and start utilizing the resource give me.your exuberance is refreshing.
Portal development Travel portal development Travel white label Travel Portal Solution B2C Travel Portal B2B Travel Portal Flight Booking API System Flight api integration

scoot said...

THANK YOU FOR THE INFORMATION .HI GUYS IF YOU SEARCHING FOR ERP Solutions
Customized Erp Solutions
CRM Solutions
Customized Crm Solutions
Seo Services in Bangalore
Website Development in Bangalore
Website Designing in Bangalore
Web designing company in Bangalore
Web Design Company in Bangalore
Website development in Bangalore
Web development in Bangalore
Web Development Company in Bangalore
Web designing in Bangalore
Web design in Bangalore
Website design in Bangalore At RT Nagar


PLEASE VISIT US
ERP Solutions
Customized Erp Solutions
CRM Solutions
Customized Crm Solutions
Seo Services in Bangalore
Website Development in Bangalore
Website Designing in Bangalore
Web designing company in Bangalore
Web Design Company in Bangalore
Website development in Bangalore
Web development in Bangalore
Web Development Company in Bangalore
Web designing in Bangalore
Web design in Bangalore
Website design in Bangalore At RT Nagar


priya said...

Live Cricket Streaming Sites

123456 said...

American eagle credit card login

kajal singh rajput said...

Download latest audio and video file fromvidmate