Hacker News new | ask | show | jobs
by gravypod 3030 days ago
I'm glad that I'm not the only one in the Java community who is extremely against `var`-like constructs. Large type inference is an anti-pattern.

People usually fight this with "why would I need to type it if the compiler can figure it out!?" but those people don't understand the cardinal rule of software engineering: code is not for the compiler or the computer to understand, it is for the programmers to understand. If this wasn't the case then more people would be using APL or similarly esoteric languages.

Adding the extra effort of recursing down the rabbit hole to find the first type being used does not sound like it will make Java more friendly.

1 comments

See the example of

Account account = customer.GetAccount();

List<Transaction> transactions = account.GetTransactions();

Have I saved you any extra-effort here by specifying the types? You have no idea where these types came from or how they are defined. So why is this useful? 'Go to definition' works just as well on var.

That is one thing. This example from the post is another:

    var customerOrderGroups =
       from(customerList)
       .select(c -> tuple(
           c.companyName(),
           from(c.orders())
               .groupBy(o -> o.orderDate().year())
               .select(into((year, orders) -> tuple(
                   year,
                   from(orders)
                       .groupBy(o -> o.orderDate().month())
               )))
       ));
Yuck! I need to read that entire thing to have any clue as to what that produces or how I should go about using it. It is compact but it is not understandable. The "Magic" of Java is clean abstractions with no voodoo. PHP/Ruby programmers like their frameworks who hide code from the developer, which layer on complexity, and which "just work" (until they stop). In a proper Java project anyone can visually see, in any part of the program, what is attempting to be done and what is being linked up to what. A big portion of this is types.

    Account account = ...;
    List<Transaction> transactions = ...;
Is all you need to read from your example. If we were to expand your ideal to a function it would look like this:

   void someFunction(var customer) {
       var account = customer.GetAccount();
       var transactions = account.GetTransactions() 
   }
I can honestly tell you that it is impossible for me to know what will happen in this program unless I go through and look at every single code path that reaches this function. Once you have entire functions, or units of code, that are using `var` it becomes entirely unmanageable. Is a string getting into `someFunction`? What about a `Trader` or a `Banker` making it's way into there rather than a `Customer`? Would you know this was happening as both Trader and Banker implement .GetAccount()?

It's no surprise though that in the world of null-propagation haven that the language maintainers would decide to expand this class of problem to all object types! Why should the null primitive be the only thing that gets to ruin our day?

'var customer' as a function parameter? You're confusing dynamic typing with inferred typing.
That code is much more scannable. The ability to scan code, to quickly glance at a method or a class and grok it in under 30 seconds is paramount. In large projects I've worked on any code that fails the 30-second test is immediately rejected at code review. Having to hover over every variable to see the types will make scanning such code in an ide a very tedious process. It will make most code review tools (that don't support such functionality) much, much less useful. I fear for the 30-second test and scanning code.
I find it much easier to scan code that uses var. Type definitions (sometimes incredibly verbose) do not help readability. And knowing the name of the type is not the same as 'knowing' the type. You still need to go to the type's definition to know what it is. Unless you have all the types in your application memorized.
Modern IDEs automatically prepend shaded type annotations for types with var. I don't believe that's an issue.
This is a poor argument for var. Competent Java programmers use the extract-to-variable keybinding (Cmd-Opt-V in my environment); it even guesses the variable name correctly.
Having the type name doesn't tell you anything about the type itself. Unless you have the type definition memorized, having the type declaration there is not very useful.

If I replaced the types above with var, you would still be in the dark as to what an Account and/or Transaction is without going to the type definition.

Eh? There's a lot of information here, even without familiarity with the code (and really, most people have at least a partial understanding of the codebases they work on).

I can see that the thing returned from getAccount() is an Account object! It's not an accountId, or the name of the account, or an AccountDTO, or an Optional<Account>, or any of the dozen other things I've seen people return from methods named getAccount().

Depending on how methods are named, the implicit documentation can be very helpful:

    Account from = transfer.getFrom();
I don't think that var is particularly evil, but I think it has a poor case for existence. Meh.
Yes? I'm fairly certain you used their account to get an ordered list of their transactions.
That exact statement could be said if there were no type definitions there. So what is the point?
I'm sorry but you are plain wrong.

var transactions = account.getTransactions();

...tells you nothing. Is transactions iterable? Is it an enum? Is it ordered? Are duplicates allowed? Maybe you're returning a basic type? Maybe it's another pojo?

The type definition alone wouldn't tell you if it's an enum, ordered, or no duplicates allowed...

The writer would know what type they're working with through intellisense. The reader would know it's iterable based on just reading the code that follows it..

So again, what does the type info give you? Most of what you mentioned you wouldn't be able to figure out from just a type name...

List<> tells me it's an ordered collection of a singular superclass that allows duplicate instances.

var tells me nothing.