Showing posts with label typing. Show all posts
Showing posts with label typing. Show all posts

Monday, August 1, 2011

Should Static Type-Checked Compilation Come to Groovy?

Please note: As always, I speak for myself alone and not as a representative for any project or company. These are my opinions and reading of an ever-changing situation.


Update: This was a pretty stupid thing to post, because everything is in flux and these are just some thoughts.

Why Should Groovy have a Static Mode?

There were some internal discussions about "Grumpy mode" among some of the Groovy committers. I had a lot of reservations about introducing static-typing or static-mode into Groovy. When I thought about the idea I come up with many unanswerable questions. Is it a good idea or not? Only time will tell. Here are some of the questions that I wish I had answers to.

What exactly do users want?

Do people want a static language with a dynamic backdoor, such as the way C#/.NET has a dynamic keyword or the way you can use Groovy++ by default with the .gpp file extension and then sprinkle in @Dynamic annotations? This is one approach, where the core of your language is statically typed but you have an option to escape into dynamic-land. Or do people want a dynamic language with a static backdoor, which Groovy will be (as far as I know) one of the few examples of. This use case is the same as adding an @Typed keyword to your Groovy code to enable static compilation, or adding an @Grumpy keyword. Or do people just want better performance from Groovy, end of story?

If you want a statically typed language without the verbosity of Java then use Scala. Yes, Scala is complex. But Groovy is just as complex. Does anyone really know Groovy without reading a few books? Yes you can get things done, but understanding metaprogramming, understanding method dispatch, and understanding all the closure options (delegates, delegate-first, trampoline) is just as complex. I am excited about Kotlin and think it looks like a great statically-typed language, but at this point it is nothing more than a slidedeck and a wiki for anyone that isn't on the IntelliJ IDEA development team. It's not available to anyone.

I honestly don't think a Grumpy mode will boost my productivity much. Will it aide in language adoption? I say probably not. In my opinion there are three large barriers to Groovy adoption in the mainstream: performance, tooling, and bugs. Not being statically typed is a connoisseurs criticism, and connoisseurs generally chase after things that are interesting rather than good (it's been said about me as well). Groovy is a language that appeals to people that just want to get something done; it's about productivity not about programming language theory. Adding static typing might please some high-end connoisseurs if it is done in a good way, but I have trouble believing it will please many real users. Search the web for "Groovy sucks". You won't find pages about dynamic type systems, you'll find performance benchmarks. In my personal experience, people I talk to about Groovy++ are asking about performance. Sure, traits are clever. Sure, the type-checking is an interesting idea. But the interest is in performance. Alex's blog posts are mostly about x-thousand transactions per second, or beating Scala performance. I think the number 1 priority of Groovy++ is performance, and type checking is a 2nd nice to have benefit.

And what about people that want a static language with a dynamic backdoor (for builder objects perhaps)? Other languages have this. C# has a "dynamic" variable, right? Boo has a dynamic variable as well, and even lowly Flex has dynamic XML support. This is useful and valuable. I would love to see an @Groovy annotation in Java, where you escape from Java into Groovy, rather than an @Grumpy annotation for Groovy. The benefit of @Groovy for Java is that tool support is the best in the world (without a doubt) and the language has a specification, is well known, and is well tested. Of course, an @Groovy annotation would only ever work with core Java language grammar changes or very ugly hacks.

Lastly, do users just want static compile-time typing for tooling support to catch silly errors as early as possible? Well yes they want that. Who wouldn't? But who is writing Groovy code without testing it? And we already do a great job of recommending suggestions when methods fail ("hashode not found. Did you mean hashcode()"). And the tools exist to do this. IntelliJ IDEA is very reliable in this regard and GroovyLint does the same thing on a limited scale. These features exist today but since they aren't in Eclipse by default then I suspect they are underused. Catching silly errors is entirely possible without the burden of static typing. In fact, some might say that the majority of CodeNarc errors fall into the silly category!

Can Groovy Afford the Complexity?

The Java world talks about a "complexity budget" where a language can only absorb so much complexity before developers leave for something simpler. The term "complexity budget" is poorly defined and often used as a scare tactic in hyperbolic arguments, but I often fear that Groovy could become the next C++ and overrun this arbitrary "complexity budget". C is a good and simple language. Java is a good and simple language. Neither C nor Java are good for all tasks, but they are both successful and capable of having system written in them. C++ started building on C and had every feature known to man added. Nowadays the criticism of C++ is that only 20% is safe to use, but no two C++ programmers can agree on which 20%. Groovy is a multi-paradigm language. You can script, you can OO, and you can FP. Already I am advising teams to find their standard. If you like FP then embrace curry, trampoline, and functions. If you don't then steer clear of those features. Adding a static mode is going to make Groovy more complex. The same code will most likely behave differently between Grumpy mode and not Gumpy. This is one more thing to think about when programming, even if we work to minimize the differences.

Looking at Groovy++, they have done some very cool things. But sometimes the basic features of Groovy++ and Groovy differ, and this cannot be allowed to happen because it is too complex. Already Groovy developers need to know Java and the JVM. I don't know how you could us Groovy outside of Grails without knowing Java. Introducing a new mode that is subtly different could be too much complexity.

Time and Budget Trade-offs

Adding static-mode seems to me like a big undertaking in terms of developer hours. Groovy++ is a good proof of concept for the idea, but the implementation won't be merged into core-groovy. The approach used by Groovy++ is to subclass ASTNodes with AST Transformations and then write out different bytecode for the node, fighting with groovyc to make sure the correct node is invoked. It is better to implement this feature as a part of the core compiler than as an AST transformation, and that is the route the team are currently taking.

It is wonderful that VMWare supports Groovy financially by giving several people jobs. But remember there are finite resources for the project. Any time spent on static-mode means there is less time spent on other features. There aren't enough hours in the day to do everything. So developing a high-performing and well-behaving @Grumpy mode means there are less resources to solve the performance problems of plain old Groovy. I already asserted that performance was a big barrier to wider adoption. Optimized ints are good for benchmarks and came out in Groovy 1.8, but I reckon most method calls are on user defined objects. How many ints are used in a Grails app? Maybe there is a way to do everything at once, but I'm a little sad to see performance improvements not come faster to the language.

My Wishlist

Here is my wishlist of what @Grumpy would do for me and how the feature should roll out.

Some social wishes...

* GEP - The GEP process for Groovy enhancements is supposed to help us formalize features and provide feedback, but it's underused. Please, let's start a GEP as soon as possible and move this big change into the public debate.

* Dev-List Discussion - The dev-list exists to give developers a forum to communicate with each other. There will always be internal conference calls and IM Chats as well, but please lets move more discussion back into the public domain.

* Research - Are there any other dynamic languages with Static backdoor that we learn from them? I don't know of one, but would love to see more examples of what works and what doesn't

Some type inference and static typing wishes...

* Closure Return Type Type-Inference - Closures should have their return type inferred. This is non trivial, and you can have closures that return the values of closure.apply(). At some point type inference breaks. Where will Groovy's fail? How far will the type inferrer go? And how will you specify a return type on a closure when it does fail?

* Closure Arity - The type checker should check the number of parameters a closure has. You should not be able to pass a one method closure to something like Collection.inject() that requires two parameters. All closures need to specify at their type declaration how many parameters it takes.

* Closure Parameter Types - The parameter types of a closure should be type checked. You shouldn't be able to pass a closure that takes a String argument to something that requires a closure that takes an Event argument.

* Closure casting to interfaces - When you cast a Closure into a Single-Method-Interface then the arity, return type, and parameter types should all be checked and verified.

* Interfaces Implemented as a Map - When you implement an interface using the Map notation [ methodName: { /* body */ } ] then the closure arity, parameter types, and return type should be checked, and the compiler should make sure all interface methods are implemented.

* curry/ncurry type issues- Functions like curry, lCurry, rCurry, and nCurry should work in a correct, statically-typed way. For example, if you curry of a 2-arg closure then you're returned a 1-arg closure. Curry a 4-arg closure and you're returned a 3-arg closure. This is a fun edge case that can't be implemented with just overloaded methods!

* Calling groovy from Java - The semantics for calling Grumpy Groovy from Java must remain sane. I'm interested to see some examples of what the APIs look like once all the new types are added. For instance, what is the Closure class hierarchy? Will there be Closure0, Closure1, Closure2 types to model the arity of closures?

* A Grumpy GDK - All of the libraries that ship with Groovy should be as Grumpy as possible. That way a Grumpy developer never has a problem just because a Groovy GDK method was not Grumpy as well. For instance, you should be able to easily make a Grumpy subclass of GroovyTestCase, so any dynamic method on GroovyTestCase should be updated to be as static as possible. Only really use dynamic features when they are necessary.

* Generic by Default - The type inference mechanism should create the correct generics for methods, similar to how F#/Ocaml creates generic methods by default. For instance, the closure: def wrap = { println "logging..."; it() } should have a generic type signature that returns the same type that the 'it' parameter returns.

* AST Transforms Can Read Types - Transforms should be easily able to read the type information out of the AST, and it should be there as early as possible in the compilation process. So the type inference should happen early. The types don't need to be checked early, but they need to be inferred early. Also, when the type of an object is unknown then an AST transformation should be able to read this. Currently, an unknown type is Object to Groovy, but there should be a difference between Object and Unknown.

* AST Transforms Can Write Types - Transforms should be able to write type information. Transforms should be able to participate fully in this process if they are to remain powerful and flexible.

* Type Verification Happens at the End - Type checking and verification should occur at the end of all the compiler phases. This enables AST transforms to actively participate in the type inferring and type specifying process. If type verification runs and fails too early then transforms that could fix the problem won't have a chance to run

So that is my wishlist, perhaps it is a connoisseur's wishlist. What is it that you want to see in Grumpy mode? What do you not want to see?

You can leave feedback here are on the Groovy dev mailing list. We'll see where this goes!

Thursday, May 22, 2008

Groovy as a Service Layer: The Aftermath

A while back I posted about why you would want to use Groovy for your service layer within a service oriented architecture. I spent the last few weeks doing just that with Axis2, and now I can look back with some perspective and confirm some of the original ideas.

My service layer moves incoming requests from untyped primitives (Strings and XML blocks) into typed Java objects consumable by a business facade, and it moves typed Java objects produced by the facade back into untyped primitives (Plain Old XML) consumable by a client. I chose Groovy based on how easy it is to produce and consume XML data within the language.

Groovy as a service
Groovy has been a joy to work with and really exceeded my expectations. The XmlSlurper class took a while learn, but using it to read XML or Axis2 OMElement objects was super easy after the first few times doing it. And generating XML with MarkupBuilder or a custom OMElementBuilder is incredibly trivial compared to the Java equivalent. By the way, writing my own OMElementBuilder turned out to be easy. Extend BuilderSupport and implement four methods. Simply put, my service classes contain much less code than if I'd written them in Java.

My original post suggested that Groovy was a better language because it was dynamically typed, thus supporting untyped data (XML) better. This isn't quite true. It is a better choice because of the XML support, which some statically typed languages also share. Scala has good support for writing and reading XML. It's hard to say anything about type systems without being proven wrong, isn't it?

Asix2 tooling
wsdl2Java is a great tool you point at a WSDL and generate reams of framework code and a single "MyService.java" pojo that will be your service class. At this point, I would take MyService.java and rename it MyService.groovy and away you go! Nothing about using Groovy has made any of the Axis2 tools break. Axis2 is instantiating your service class using reflection, so as long as you produce a class file with the correct public method, then you're good to go. Scala services should work just fine too, as well as JRuby (I'm guessing). HOWEVER! The default "MessageReceiver" in Axis2 invokes your service method using reflection. This means your sweet metaprogramming invokeMethod tricks will not work. That took me a while to figure out.

That being said, I turned all that SOAP cruft off and just used the existing raw XML message receivers. Eventually I threw that out and wrote own. Just another case of Not Invented Here? Possibly. But it was the only way I could get my MessageReceivers created out of Spring (a post for another day, sigh).

REST vs. SOAP
Axis2 support for REST was underwhelming. Under the covers, the REST request is converted into a SOAP envelope for you. So your "MessageReceiver" always sees a SOAP message, even when you're using REST. Also, only POST and GET work. After looking breifly at Grails url mapping and REST support, I would encourage someone to use Grails instead of Axis2. We don't always have the authority to make these decisions though. I know I don't.

Mixing Groovy and Java classes
I never understood the Groovy joint compiler until now... My project has Groovy classes that reference Java classes and Java classes that reference Groovy classes. The joint compiler runs through the Groovy code and generates Java stubs for all your Groovy classes. Then it compiles the Java classes against the stubs so that Java has something to link to. Lastly, it compiles the Groovy code into real classes and replaces the stubs. Nifty, although sometimes you'll have MyClass.groovy and receive a compiler error referencing MyClass.java. That'll confuse you the first time!

I also felt Groovy's optional static type system really helped the Groovy classes integrate into the existing Java codebase. My goal (and constraint) was to write Groovy based service classes and leave the rest in Java. As my Groovy classes grew, and code started being refactored into reused components, I started tightening down the compile time contract of the shared code to make it more usable. My first step was to declare return types on methods. This made the calling code a little easier to work with. On some classes I eventually stripped out the Groovy specific libraries and converted them into pure Java classes (.java extension and all). It was great that I could have the thought, "Oh, I really should have written this in Java" and then actually convert the thing to Java within a few minutes.Although, by and large, my more common thought was, "I wish I could just do this in Groovy" rather than vice versa. But as I said, we don't always have the authority to make these decisions. However, a few of my classes can't be converted to Java because of the reliance on metaprogramming. If you're cautious, you might avoid putting yourself in this situation. I say go for it.

Lastly, I work in an IntelliJ IDEA shop. Having the great Groovy plugin for IDEA helped immensely. This would have all be a lot harder if you were switching IDEs or editors based on language. Being able to step through code from Java to Groovy and back again, as well as navigating the whole project as one unit, made the whole process work a lot better.


Big thanks to everyone who left a comment or contributed on the discussion on the Groovy.mn mailing list. You helped a lot!

Thursday, December 13, 2007

Like: The Missing Operator?

I've always been slightly skeptical of claims that thorough unit tests in dynamically typed languages are a replacement for the guarantees that a static type checker offers. In the simple case it seems to work fine, but as examples get more advanced I start to feel uneasy. For instance, consider the following Groovy test method that produces an object representing an email message:

def server = new MailServer()
def message = server.getNewestMessage()

assert message.to == ["hamletdrc@gmail.com"]
assert message.from == "hamletdrc@gmail.com"
assert message.subject == "note to self"
assert message.body == "sample message"
This unit test seems to thoroughly exercise the message object, and I doubt many people would feel the need to test message beyond this. But what if the message object is defined with a truncate method and not just fields:
class Message {

def to = []
def from
def subject
def body

Message(to, from, subject, body) {
this.to.addAll(to)
this.from = from
this.subject = subject
this.body = body
}

def truncate = {
new Message(to, from, subject, body.substring(0, 50))
}
}
Is the original test enough? What if the message object returned from the server doesn't have a truncate method? What if, instead of an actual Message object, one of the methods returned a closure map:
def getNewestMessage = {
def message = inbox.get(0)
return [
to: message.to,
from: message.from,
subject: message.subject,
body: message.body
]
}
The unit test will still pass, but any calling code in production receives a nice runtime exception when attempting to call truncate. There are no guarantees on the contract of types in dynamic languages, but this is exactly the sort of thing a static type checker would enforce. It has always seemed to me that if unit tests are indeed a replacement for a type checker then those unit tests should guarantee that the contract is followed. It would be a monumental task to ensure in tests that all expected methods exist on an object. This is what makes me feel uneasy about claims that unit tests are a replacement for a type checker.



Enter ECMAScript 4 and the like operator. ECMAScript 4 contains a like operator that is a sort of weak instanceof. I stumbled upon it in the paper Evolutionary Programming and Gradual Typing in ECMAScript 4. The like operator is an assertion that a certain object looks a certain way at a certain time. For instance, an arbitrary object is "like" a java.lang.String if its set of public methods and fields contains the set of methods and fields on String. It is not an "is" comparison, rather it is just checking to make sure an object adheres to the declared contract of another. The "point in time" distinction is important, because the object could have methods added or removed later.

This intrigued me. With the inclusion of a like operator in unit tests, you could claim that those tests are a replacement for the type checker. Imagine the test rewritten:
def server = new MailServer()
def message = server.getNewestMessage()

...

assert message like Message
I was interested enough to actually try to write a like operator, (short sighted enough, as it turned out). Or, since I can't really write an operator in Groovy, I'd write an assertTypeLike assertion method to use in my Groovy tests.

It started out simple enough... Groovy 1.5 includes a new class called Inspector. This allows you to get real and virtual methods on objects. Create a list of public signatures on the test object, create the same list from your control, compare, and viola, a type like comparison.

Except that this turned out to be really, really difficult. There are a ton of edge cases. A HashMap of closures can be treated as an object. Methods on an object can be defined as closures. One method interfaces can be implemented as closures. The list goes on. But the killer is that my solution totally ignored metaprogramming with either invokeMethod or methodMissing.

Had I thought a little harder, I would have realized that a like operator will never work in a language like Groovy. Since any method call can be intercepted and responded to, even those that don't exist, it is not possible to analyze the structure of a class and determine if it fulfills some contract (or even if it has a contract for that matter!).

The like operator is a cool idea. I feel Adobe has been trying to placate both sides (dynamic and static) by taking a best of both worlds approach to ActionScript. Promoting a type system that can be gradually enforced stricter and stricter as a project grows is one example of this. As someone coming from a C++/Java background, this appeals to me! But would I give up metaprogramming for this? Not a chance!

In the end I have to ask myself, what am I trying to prove? Am I trying to prove that my software works correctly for my customer? I am, and unit tests are essential to this, not a type checker. Am I trying to prove that my objects won't blow up if called in a certain way that I don't expect? The like operator can help me here, but I DON'T have this problem. I can't point to a single production issue that the like operator would have saved me from. So why in the world does my mind keep pushing me to test types in this way? Perhaps this is my Java mind clinging to the comfortable. If you have better ideas then let me know! In the meantime, I'm going to continue coding without the safety net.

As a parting comment, page 2 of the paper contains the funniest definition of duck typing I've seen yet:

This kind of type discipline is often known as "duck typing", on the principle that if something walks like a duck and talks like a duck, it is a duck. (This should not be confused with an older and now discredited type discipline, which says that if a woman floats like a duck then she's a witch. ES4 has no objects that flot like ducks, but it does have floats that bewitch - decimals.)

Awesome. My groovy test case for assertTypeLike can be found here.

Monday, October 1, 2007

XML: A Retarded Innovation

"XML is a prime example of retarded innovation; it makes the life of the low-level plumbing infrastructure easier by putting the burden on the actual users by letting them parse the data themselves by having them write an abstract syntax tree, introducing an alien data model (Infoset) and an overly complicated and verbose type system (XSD) neither of which blends in very well with the paradigm that programmers use to write their actual code. "

-Erik Meijer and Peter Drayton

In public tonight, I laughed audibly at this quote from Meijer and Drayton's draft paper Static Typing Where Possible, Dynamic Typing When Needed: The End of the Cold War Between Programming Languages. This is a spot-on criticism of XML expressed in a single sentence (try to ignore the semi-colon and run-on sentence in the second clause). The paper isn't actually about XML though. It is a guide to features that static typing affords and features that dynamic typing affords, and discusses when to use which.

The authors surprised me by dispelling two common myths about dynamic languages: that they enable lazy evaluation and enable higher-order functions.

The lazy evaluation myth is the thought that loose typing makes it easier to create complex applications by gluing together small components. The common example is the power of Unix shell programs. Because all programs take a simple byte stream as input and output, it is possible to chain any number of Unix programs together and create a meaningful result. It would not be possible to pipe commands together if the byte stream contained complex types (think serialized Java objects) because each program would need to know the format of the objects. So what is the myth? Unix shell programs are powerful, and the input/output of the programs doesn't contain type information... Well, the real power of Unix scripts isn't their input and output format, it is the fact that they produce lazy streams of bytes. The example of ls | more is powerful because the more program doesn't wait until the ls application is finished to begin doing work. If this were the case then the entire output of ls would need to be stored in memory somewhere (performance drain), and the more program would not start displaying until after the entire command had finished (liveness issue). So the real power in Unix programs is the lazy streams, where data is passed to programs as it is available rather than when the batch is finished. In fact, the lack of type information in the stream is a drawback because it limits what the program can do with the data. Lazy evaluation is the power behind lazy lists, Unix pipes, and asynchronous messaging systems.

Hey, and there is one more reason why XML is so rotten: XML cannot be validated until the entire XML document has been read. This means that any operation on XML data should wait until the entire stream is created and parsed, thus ruling out lazy evaluation.

The power to be had from lazy evaluation has nothing to do with dynamic typing... possibly the opposite. Since the .NET CLR and the Java JVM are so similar at the execution level, it would be possible to define a common, and more advanced, data language that provides more power than simple byte streams. But XML ain't that common format!

The other myth explored is the idea that dynamic languages have better support for higher -order functions than static languages. The ability to dynamically eval strings as programs is powerful, and the ease at which it can be done in dynamic languages is striking. It is exciting the first time you pass an algorithm around as a parameter, or store one as a variable without having to resort to the strategy pattern. But a string isn't a function, a string is a data format. And passing a string into a function to be eval'd isn't a higher-order function, it is a substitute for it. Not only is this often unnecessary, but it is also dangerous. The SQL injection attack is an example of untrusted source that relies on eval and strings to work.

The truth is, any language that can dynamically load code can perform runtime code generation to create a higher-order function. In Java, it can be done with dynamic class loaders or native DLLs, and without having to use Strings and an eval method.

Exploring these two myths wasn't even the main point of the article, so if you're at all interested then go check it out. It is definitely in draft form, but it is good reading nonetheless.

Friday, July 13, 2007

Observer in the Wild

The Design Patterns book study group I participate in met last week and discussed the Observer Pattern for an hour.

The Observer Pattern appears frequently in GUI development, and most people are at least familiar with the Swing style MouseListener interface (or others like it). Basically, a client object declares itself to be an observer (listener) and passes itself off to an observable subject. The subject keeps a list of all observers and notifies them when some event has occurred.

Be cautious in thinking that this is a pattern that needs to be emulated. There are a lot of different ways to implement the Observer Pattern beyond this common method. In fact, as Stuart Halloway recently pointed out, some languages are sufficiently advanced (or just different) to have no need for this pattern at all.

One Java compatible alternative implementation is to not require the observers to declare a specific interface and instead use reflection to notify listeners that an event has occurred. This may sound suspect on the surface… but consider it for a moment. If a method name were invoked reflectively then there is little advantage to not declaring an interface… it just makes the Observer pattern harder to understand and harder to support in an IDE. But if method parameters are analyzed instead, then you get several advantages. One, the Observable object is not coupled to any specific client interface, and any object at all can become an observer of events. Kinda nice. Two, parameters can be analyzed and the most specific method can be called for the event. For instance, if you have a listener of cascading style sheet property events, and want to be notified when a property changes, then you may have a listener of a CSSChangeEvent… or maybe you only want a CSSFontChangeEvent, which is a more specific sub type of the change event. Traditionally, the listener would have to analyze the observable object to see if the event was /really/ want it was interested in or cast the data sent to it to perform the same check. Ugly, but totally acceptable in the Java world because that’s the way it is done. Using the parameter reflection scheme cleans up the code considerably because methods can declare specifically what types of events they are interested in and the Observable object can suppress events that the listener doesn’t care about; all while still being extremely loosely coupled with that listener. Before writing this off as a hare-brained scheme, consider that the Spring framework for .NET uses a very similar mechanism for their observer implementation. The code base I work on has a similar version also. Of course, there are a few problems with this. Method parameters may be ambiguous, and how the “most specific” method is determined must be documented somewhere… AND the programmer must somehow know to read the documentation (yeah, that’ll happen). Also, IDE support for this does not exist and things like Find Usages and automated refactorings won’t work. A final problem has to do with typing. At what point does the observable check to make sure that the listener actually has a method that can be called? The Java world adheres to the fail early/fail fast error handling principle, so the initial inclination would be to check the listener as it is registered to make sure it has an event handler method that can be called. But as Groovy gains usage, it would be possible to register a Java/Groovy object with an Observable that does NOT have valid callback methods and then later dynamically add those methods onto the object as a mixin. Far fetched, I know, but technically possible. An open discussion point from the meeting is whether or not this parameter reflection theme constitutes “Duck Typing“, but I’ll leave that for the comments section below.

A second alternative that is not Java compatible is to use closures. But when Java 7 is released it just may be part of the language! In many languages, a method is a first class citizen of the object world: it can be passed as a parameter, returned from a function, declared as a variable, and stored as an item’s state. C++, SmallTalk, JavaScript, Ruby, and Groovy all have some construct like this (plus many other’s, I’m sure). ActionScript 1.2 in Flash performed all of their event listeners like this. The variation here is that instead of creating a small, anonymous class to be a listener, you simply create a small, anonymous method.

Your code goes from:

component.addCSSChangeListener(new CSSChangeListener(){
  onFontChange(){System.out.println("font changed");}
});

to something like:

component.addCSSChangeListener({
  System.out.println("font changed");
});

Closures open up a whole lot of new programming techniques. It is a big change that may or may not be added to the language. If it does, a lot of the interface based programming that we do can be streamlined to be closure/method based. Of course, you can write FORTRAN code in any language you want, and you will always be free to use obsolete constructs with languages that don’t require them. For instance, I googled “Ruby + Observer” and found quite a few examples showing how to implement an interface based observer pattern in Ruby code. I’m sure there is a time and place where that is needed, but a language that provides closures should obsolete this pattern.

A final option, that even less languages support, is to handle observers using pattern matching functions. Some languages support what is called Pattern Matching in method parameters... so dynamic dispatch doesn’t occur simply on the object type, but based on the value of the object too. For instance, consider the following if statement:

void foo(int x) {
  if (x == 0) {
    print("zero");
  } else if (x == 1) {
    print "one");
  } else
    print(x);
  }
}

In a pattern matching language you could instead write it like this:

void foo(0) {
  print("zero");
}
void foo(1) {
  print("one");
}
void foo(int x) {
  print(x);
}

This means that you could declare your listener object to have the method expected, and have the events it wants to handle in the parameters of that method. No if statements, no casts, and no inspecting the Observable to see what event was generated. This has all the advantages to the first option discussed (reflection based on parameters) except that the language supports it instead of having to use reflection and then defining your own parameter precedence level. Also, dynamic dispatch isn’t based on solely object type, but the values of that type as well. So, using the previous CSS handler example, you could have one method that handles changes to the “Tahoma” font, one method that handles changes to any font, and one default method to handle everything else. Ultimate flexibility, and the Observerable is still loosely coupled to the observer because there isn’t even an interface declared that it is dependent on (assuming a weak type system). This is the language feature I want!

So, Java programmers (that’s you), which of these observer patterns is the most awful? Which one would have you cursing the original developer when you’re trying to maintain the code years later? Feel free to let loose...