re: Modernizing Java - A language feature wish list (Part 1) VIEW POST

re: Thinking from the POV of starting out in an existing codebase that uses these features, I’m not sure I agree with all your points. Extension metho...

Thanks for the response! I agree that some of the features I described in this blog post (in particular strict null-ness) are only intended for new projects. Then again, this is a long-term wish list, we all know that Java isn't exactly the fastest-moving language out there when it comes to the introduction of new features.

Extension methods: I can only talk about the Xtend-case here, I've yet to see this feature in another language working in this fashion. In Xtend, you still have to import the utils classes you want to use; that alone limits the room for misunderstandings. In the Xtend IDE, the call to an extension method is highlighted slightly differently than a regular method call, so it's always clear what you are calling. If in doubt, a quick "jump to declaration" will give a definitive answer to what is being called here. Here's another example why extension methods make life so much easier:

// Java 8 (ok, but super verbose)
List<String> lowercased = myStrings.stream().map(String::toLowerCase).collect(Collectors.toList());

// Java 8 with static utils
List<String> lowercased = CollectionUtils.map(myStrings, String::toLowerCase)

// with Xtend-style extension methods:
List<String> lowercased = myStrings.map(String::toLowerCase);

Strict null-ness: The way this works in Ceylon under the hood is by using so-called Union Types. null is not assignable to any class in Ceylon, other than Null (i.e. it has it's own class). When you define a parameter as User?, it is a shorthand for User | Null, i.e. "this paramter has to be a User or null". A method call on a variable of a union type is only valid if all type members of the union support the method. Any method call, e.g. getUsername(), is invalid on a parameter variable of type User?, because Null defines no methods. So how do you transform User? into User? Flow typing has you covered:

   User? user = userService.loadUserById(1234);
   // user.getUsername() is illegal here because of union type with NULL
   if(user != null){
      // flow typing narrows union type down from (User | Null) to just User...
      user .getUsername(); // ... so this is ok here

Similar concepts were introduced e.g. in TypeScript. And yes, this check can break existing code bases. It's an opt-in compiler feature and migrating an existing code base is not always easy. However, I've seen an interesting behaviour in programmers. Let's say method a(obj) calls b(obj), and b(obj) in turn calls c(obj). c cannot deal with null parameters. Therefore, b will get a compiler error if it tries to pass it's nullable parameter into c. As a consequence, programmers tend to forbid the parameter of b to be nullable. Then a has an error, and so on. The treatment of nulls is shifting automatically and intuitively to where it belongs: towards the I/O handling at the system boundary.

code of conduct - report abuse