Classes final by default

No matter which direction this goes, the discussion here gives me great optimism for a vibrant community going forward.

This is correct - some subset of your own application logic is subject to dynamic proxies. Unfortunately this set isn’t always as fixed as it might seem. I’ll give a couple examples from Spring. (For those that don’t like Spring: I beg of you to put your dislike aside for a moment and see the general applicability to any other framework that uses dynamic proxies for useful value-adding purposes)

  1. @Configuration annotated classes must always be opened, because they are invariably proxied. This is a rather quick rule that any developer operating with Spring and Kotlin will learn early on.

  2. Pretty much any other injectable resource in Spring may or may not be proxied, depending on what set of features you happen to be using. So if I start with a simple Boot application with only Spring MVC, I don’t have to open my @RestController classes. If I wish to add something like Hystrix fallbacks or Spring AOP, something that was previously not proxied now may be proxied depending on whether it is applicable to the feature.

In both cases, I am most allergic to the fact that I discover the finality problem at runtime. To me, the more a language can prove to me the correctness of my code before runtime, the closer it is to perfection. In Kotlin, for example, I don’t find myself writing as many defensive unit tests around null behavior because Kotlin’s null handling eliminates certain classes of problems in this space. By enforcing closed-by-default, Kotlin opens up a new class of problems that I need to add tests for, lest I be surprised at runtime.

I think this idea of monkey patching third party libraries is the basis of the theoretical argument for closed-by-default, but the one I see the least carried out in practice.

3 Likes