Hacker News new | ask | show | jobs
by SmellyPotato22 1961 days ago
I disagree with claim that One letter generics are a bad habit. In my opinion, it is proper to use one letter generics but start with A then B, then C... so it enables to reason about generics positionally. Pseudo example of this:

`map<A,B>(fn:(el:A)=>B):B[]`

5 comments

I wouldn't agree they're a bad habit either, but only when used with care. Types like T, and K, V might be as clear to most people as i and j in array operations.

Your example is clear enough because the signature is simple, but in more complex functions I've found that becomes obscure real fast, particularly if types are then passed down to something which also uses generic types. Enabling people to reason about things is not as clear as actually telling them what it is. If the 2nd of 3 generic types is the return type for whatever reason, call it SomethingReturn type and remove that ambiguity.

I think I agree with you (though I would favor T, U, V as the sequence).

What would the alternative look like in what you wrote? In and Out? Range and Domain? Generic type variables are often too abstract to give a sensible name to.

This is the one "bad habit" that I think is a bit silly - naming conventions can vary by project.

In the context I am thinking about, writing a generic iterator, you have 0 context of the what the concrete types will ever be.
Hard disagree. Having come into a TS codebase from the outside that made liberal use of generics, they can make things incredibly difficult to follow if they don't have really good naming and/or docs.
Yes. But do long names even help? I imagine, in such a project the system of generics can be so complex that a new dev cannot use them to their intent without completely understanding the code.
You could say the same thing about variable names:

"But do long names even help? I imagine, in such a project the system of logic can be so complex that a new dev cannot use them to their intent without completely understanding the code."

Meaningful names help a person gain an understanding of the code. And that's not even getting into whether or not "completely understanding the code" is a tractable goal in the first place (I don't think it is, even for the people who wrote the code, much less those who come later)

Long variable names don't help either. It's been mostly a stylistic choice and a recent trend that stylistically long variable names are nice. But there are plenty of projects that use short variable names or even one letter names, and I don't see any evidence that those projects are less productive because of it.

The actual research is that long variable names make it harder to understand code. It makes the variable name become an integral part of any code snippet that a reader feels compelled to memorize the specific names used, and that memorization results in errors and increased recall time.

Short variable names, including single letter names, allow a reader to basically ignore the name itself which allows them to accurately memorize an entire chunk of code without feeling the need to memorize long names. This improves recall time.

In simpler terms, when a snippet of code uses descriptive variable names your brain is inclined to believe that those names matter and that you need to remember them, compared to short variable names that your brain will not have to bother remembering and instead frees you up to focus on the structure and semantics of the code snippet.

The study that you can read, which is quite insightful is here:

https://pdf.sciencedirectassets.com/271600/1-s2.0-S016764230...

Note that long function names DO help, but long variable names do not.

That said, feel free to use long variable names if that's what you like and your project does it that way. Don't, however, express that as some kind of extensively studied software engineering principle that has research backing it. It's basically one of those things someone decided was true and everyone else just decided to believe it without ever doing the kind of work needed to validate the hypothesis.

In software engineering, we are still in the days of Aristotle, where we simply believe things to be true because we want them to be true. Just like the days of Aristotle I wouldn't be surprised if it takes us literally thousands of years before someone comes along and decides to question and test basic assumptions we all take for granted.

Your link appears to be broken

We can debate the value of one-word (or even acronym) vs five-word variable names, but the key factor in my view is that the name holds some sort of intrinsic meaning to the person looking at it, vs being an arbitrary symbol. For example, x and y - despite being one-letter variable names - are perfectly sensible in a context where you're talking about euclidean geometry and referring to values on the x and y axes. But they are not reasonable names in the context of business logic where they represent customers or transactions. Alternately, a software shop may establish a convention that generics A and B mean something specific across all contexts in their codebase. A company-specific convention this arbitrary will still increase the barrier for newcomers to comprehend the code, but once learned they will at least be able to re-use the knowledge and A and B will become meaningful to them. In this way, "meaningful" may be relative. Usually meaningful names will take the form of one or more words, but not always; I wouldn't say the actual length itself is what's important.

With that established: by choosing names that have intrinsic meaning to the reader, the reader's mind is allowed to skip a step of indirection where they would otherwise have to perform a mental "dictionary lookup" from symbols to concepts. To be frank: study or no study, it's literally unbelievable to me that removing this step wouldn't help the slightest bit with both comprehension and recall.

Addendum: There's a further dimension to this which is that code is more than what it does. Take the following function:

  function m(a, b) {
    if (a < b) {
      return a;
    } else {
      return b;
    }
  }
Is this code wrong?

Because the function lacks a meaningful name (or documentation), it's not simply hard to tell, it's a question with an undefined answer because the intent is not represented in any way. This function currently returns the minimum of the two arguments, but there's no indication whether it was meant to return the minimum, or the maximum, or even the sum for that matter.

Maybe you could argue that we should be writing comments anyway, but that still moves the meaning across a step of indirection, where you have to go find it instead of seeing it inline. We absolutely should be writing comments, but they don't completely replace good naming.

By all means, use long or short or whatever consistent naming convention you'd like, even with the study I provided, the difference is not going to make or break any project.

All I'm saying is that as professionals, there is a mismatch between how strongly we believe things to be true and how much time and effort we invest in validating those beliefs. People here will argue very strongly about long vs. short variable names and this discussion could go on and on and on, but no one here will actually try to find existing research or conduct any research of their own.

My position is until you, or me, or anyone wishes to hold a strong belief about what is truly beneficial in terms of productivity, human psychology, etc.. we should hold off on making claims about objective engineering facts and instead simply accept that our claims are stylistic in nature and used out of consistency and convention, rather than because we have evidence that it's superior.

Finally, it really is worth noting that it was literally unbelievable to Aristotle that heavy objects fall at the same speed as light objects, so much so that no one bothered to test that assumption for thousands of years.

If you, or anyone, is so convinced that some coding convention is more than just stylistic but actually objectively superior, why not put in some degree of effort to conduct a scientifically reliable test to validate your belief? If the answer is that it's too hard to put in the work to objectively validate your opinion, then you should also accept that it's too hard to accept your opinion as an objective fact.

If we as professionals are not willing to validate our beliefs in a rigorous manner, then we as professionals should not feel so compelled to proclaim those beliefs as being objectively true instead of simply a matter of preference.

> It makes the variable name become an integral part of any code snippet that a reader feels compelled to memorize the specific names used

And single character variable names don't require memorisation? raises eyebrow

Do you also use one letter variables and parameters? If not, what is different about generics?

Even in your example, I'd rather read this:

map<IN,OUT>(fn:(el:IN)=>OUT):OUT[]

Plus, it really is a habit. If you stop doing it for these kind of examples that really are very generic, maybe people wouldn't also use only one letter for cases where there is more of a difference between them.

Sometimes I do, sometimes I don't. If it's an iterator I often use one letter names such as i, j, k. Similarly if it's a generic unbounded type I also give it a one letter name.

  > Do you also use one letter variables and parameters?
A question in response to your question... Do you ever give an ALL CAPS name to a class? Why not?

Maybe it's the set of conventions I'm used to, but I find T, U, V familiar and IN, OUT jarring and dramatically less readable at a glance.

It might be 'jarring' but looking over the original line I didn't parse what those types were doing at all, and T/U/V wouldn't be any better, while IN/OUT I can understand without explicitly thinking about it.
I use ALL_CAPS in generics so they are easy to tell apart from functionNames and ClassNames
Kinda gets a little hairy if you start to add more types. Example: `//fork :: [a] ->((a -> b ), (a -> c)) -> ([b] ,[c])`

`fork<A,B,C>(fn1:(el:Iterator<A>)=>B,fn2:(el:Iterator<A>)=>C)`

What would be the opposite of "fork", something like "zip" that gets two lists and combines them into one? Would it have a signature also starting like this: `zip<A, B, C>(...`
I think that about right. Although I think this is slightly different than regular zip which is [a] -> [b] -> [(a,b)] and instead would be ([a],[b]) -> [c] or if I remember currying right [a] -> [b] -> [c].
Agree, generic name should mirror its meaning.

For generic that doesn't have any specific meaning we can use T.

Adding a meaning to meaningless generic will add confusion, like in the example, Element might conflict with HTMLElement while it can be something else entirely.