SUMMARY: Kotlin has given us a fresh perspective on some very ingrained OO-habits, particularly the pervasive use of nouns for objects that have only one public method.
Speaking like a native
Pronouncing a foreign language so convincingly that you can pass for a native speaker is one of the hardest tricks to pull off. While it comes natural to young children it is something that very few adults ever master. That is because our ears have become attuned to the speech habits of our native language and we interpret every foreign language according to these patterns. While European mouths are perfectly capable of producing the idiosyncratic sounds of, say, Mandarin Chinese, your ears can’t hear the subtleties unless you train to distinguish the subtleties. Heck, even the Dutch, who pride themselves on their English skills struggle with the differences between bet, bed, bat and bad. Actually, the real problem of having a thick foreign accent is that you don’t struggle with the unfamiliar sounds. You’re simply not sufficiently aware of their difference.
In software it’s equally hard to teach an old dog new tricks. Oracle gurus see the world as a bunch of tables and foreign key constraints. Old school OO-programmers think of thingies with state and behaviour. Functional-language purists think like … eh … Vulcans, I suppose. Whenever you pick up a new, more expressive language than the one you’re used to, it takes time to master it like a native.
Leaving the kingdom of nouns
Take the good old Gang of Four design patterns. Kotlin has given us a new perspective on them. It all looks much leaner, with less boilerplate, but the familiar templates are still firmly rooted in the realm of OO with their familiar nouns like Delegate, Composite, Visitor and Command, i.e. all nouns.
In Java the noun is King, according to Steve Yegge’s amusing rant. Like kings, nouns delegate all the real work to methods. They aim to do as little as possible, because the more coherent of purpose an object, the better. So we end up with tiny Liechtensteins and Monacos that do only one thing well (money laundering, I suppose). This opens up new opportunities, because when there’s only one method, it doesn’t much matter what it’s called.
The command pattern is all about objects that do only one thing, long before Java had lambdas and the @FunctionalInterface annotation. It’s good practice to call that method execute(), but I’m sure others have called it makeItThus(), doIt(), getOnWithIt(), just to point out that the name is redundant.
Kotlin has taken a wise decision: you should be able to invoke these single methods without mentioning their name. There are two flavours, one with a functional interface and one with the operator notation. I like the first one better, because it makes the nature of the class immediately clear: BitCoinToDollarConverter turns one number into another.
class BitCoinToDollarConverter : (Double) -> Double { override fun invoke(bitcoins: Double) = bitcoins * 10000 * Random().nextDouble() }
or
class BitCoinToDollarConverter { operator fun invoke(bitcoins: Double) = bitcoins * 10000 * Random().nextDouble() }
Scala follows a similar path, with the apply() function.
Great! I have a similar Spring service that converts hibernate entities objects to JSON DTOs.
@FunctionalInterface interface Converter<out D, out D : DTO> : (E) > D @Service class PreferenceToDto : Converter<Preference, PreferenceDT> { override fun invoke(preference: Preference): PreferenceDTO = … }
I can autowire the service and invoke it in two ways
@Autowired lateinit var converter: PreferenceToDto ... val dto = converter.convert(someEntity) val dto2 = converter(someEntity)
But the converter reference is just an old, ugly OO habit: what we have looks like an invocation of a local or inherited method, but is actually a method called on an object. Why not relax the old habit that object references should be named with a noun? Do I care that converter is a reference to a single-method object? No, I care about what it DOES. For that we use verbs.
val dollars = convertToDollars(0.543) val dto = convertToDTO(entity)
If it looks like a duck, and quacks like a duck — even when it’s not a duck — call it Donald.