Hacker News new | ask | show | jobs
by foooorsyth 529 days ago
Not everyone reading your code will be using an IDE. People may be passively searching your code on GitHub/gerrit/codesearch.

val/var/let/auto declarations destroy the locality of understanding of a variable declaration without an IDE + a required jump-to-definition of a naive code reader. Also, a corollary of this problem also exists: if you don’t have an explicit type hint in a variable declaration, even readers that are using an IDE have to do TWO jump-to-definition actions to read the source of the variable type.

eg.

val foo = generateFoo()

Where generateFoo() has the signature fun generateFoo(): Foo

With the above code one would have to jump to definition on generateFoo, then jump to definition on Foo to understand what Foo is. In a language that requires the explicit type hint at declaration, this is only one step.

There’s a tradeoff here between pleasantries while writing the code vs less immediate local understanding of future readers / maintainers. It really bothers me when a ktlint plugin actually fails a compilation because a code author threw in an “unnecessary” type hint for clarity.

Related (but not directly addressing auto declarations): “Greppability is an underrated code metric”: https://morizbuesing.com/blog/greppability-code-metric/

4 comments

If you accept f(g()), you've already accepted that the type of every expression is not written down.
I don’t particularly accept f(g()). I like languages that require argument labels (obj-c, swift). I would welcome a language that required them for return values as well. I’d even enjoy a compiler that injected omitted ones on each build, so you can opt to type quickly while leaning on the compiler for clarity beyond build time.
Argument labels are equivalent to variable names. You still have them with auto. In either case you don't see the actual type.
I do not agree that using an IDE matters.

If you cannot recognize the type of an expression that is assigned to a variable, you do not understand the program you are reading, so you must search its symbols anyway.

Writing redundantly the type when declaring the variable is of no help when you do not know whether the left hand side expression has the same type.

When reading any code base with which you are not familiar, you must not use a bad text editor, but either a good text editor designed for programmers or any other tool that allows fast searching for the definitions of any symbols encountered in the source text.

Adding useless redundancy to the source text only bloats it, making reading more difficult, not easier.

I never use an IDE, but I always use good programming language aware text editors.

The argument is tautological.

I want to use a text editor => This is the wrong tool => Yes, but I want to use a text editor.

These people do use the wrong tooling. The only way to cure this grievance is to use proper tooling.

The github webui has some ide features, such as symbol search. I don't see any reason why not use a proper ide. github.dev is a simple click in the ui away. When you use gerrit, do a local checkout, that's one git command.

If you refuse to use the correct tools for the job, your experience is degraded. I don't see a reason to consider this case when writing code.

Have you ever worked in a large organization with many environments? You may find yourself with a particular interface that you don’t know how to use. You search the central code search tool for usages. Some other team IS using the API, but in a completely different environment and programming language, and they require special hardware in their test loop, and they’re located in Shanghai. It will take you weeks to months to replicate their setup. But your goal is to just understand how to use your version of the same API. This is incredibly common in big companies. If you’re in a small org with limited environments it’s less of an issue.
I have worked in big environments. My idea about "big" might be naive, environments spanning different Oses and different, including old languages like fortran and pascal. But I never been in a situation where I couldn't check out said code, and open it in my ide and build it. If you can't that sounds like a another case of deficient tooling. Justifying deficient tooling.

These where not some SWE wonderlands either. The code was truly awful at times.

The Joel test is 25 years old. It's a industry standard. I, and many other people consider it a minimum requirement for software engineering. If code the "2. Can you make a build in one step?" requirement i should be ide-browsable in one step.

If it takes weeks to replicate a setup the whole environment is deeply flawed. The one-step build is the second point on the list because Joel considered it the second most important thing, out of 12.

My situation: hardware company, over 100 years old. I’ve found useful usage examples of pieces of software I need to use, but only on an OS we no longer ship, from a supplier we no longer have a relationship with, that runs on hardware that we no longer have. The people that know how to get the dev environment up are retired.

In those cases, I’m grateful for mildly less concise languages that are more explicit at call and declaration sites.

If you are unable to find the type of a right-hand-side expression that appears in an assignment or initialization, then the environment does not allow you to work and it must be changed.

The redundant writing of the type on the left-hand side does not help you, because without knowing the type of the right-hand side you cannot recognize a bug. Not specifying the type on the left-hand side can actually avoid many bugs in complex environments, because there is no need to update the code that uses some API, whenever someone changes the type of the result, unless the new type causes some type mismatch error elsewhere, where it would be reported, allowing to make fixes at the right locations in the source code, not at the spurious locations of variable definitions, where updating the type will not prevent the real bugs to occur at the points of use of that variable.

The only programming languages that could be used without the ability of searching the definition of any symbol, were the early versions of FORTRAN and BASIC, where the type of a symbol was encoded in the name of the symbol, by using a one-letter prefix in FORTRAN (like IVAR vs. XVAR) and a one-symbol suffix in BASIC (like X vs. X$ vs. X%).

The "Hungarian" convention for names used in early Microsoft Windows has been another attempt of encoding the types of the symbols in their names, following the early FORTRAN and BASIC style, but most software developers have disliked this verbosity.

> if you don’t have an explicit type hint in a variable declaration, even readers that are using an IDE have to do TWO jump-to-definition actions to read the source of the variable type.

This isn’t necessarily the case. “Go to Definition” on the `val` goes to the definition of the deduced type in the IDEs and IDE-alikes I’ve ever used.