chaboud 3 days ago

I thought this was going to be a bit of dry humor before I followed the link. It’s actually serious, and fairly informative (albeit a bit scary).

The first place I worked had a soft-but-hard rule (enforced by ridicule) that single-letter variable names not be used. Loop counters like i, j, and k were frowned upon. However, counters like ii, jj, and kk were fine for matrix operations, xx and yy for image loops, etc.

There were a couple of key guidelines to follow:

1. If it can have more meaning than sample, pixel, or matrix position, give it more meaning, but two characters repeated is fine for loop counters (again, with meaning).

2. Whatever you use should be quickly findable with text search tools of the era (the late ‘90’s).

Someone shouldn’t have to use source inspection assistive coding tools to parse the code you write. When someone else (or you, in a few months) comes upon this code and needs to understand it, they should be able to use find to do it.

  • liampulles 3 days ago

    If I'm looking at a for loop, my expectation is that the loop variable will be i. I'm against single letter vars as a general rule but I think this is a fair exception

    • bluerooibos 2 days ago

      I'd prefer i to be a description/name of the thing that is being iterated.

      If your array is named cars then you can safely assume i will be a car, but depending on the complexity of the code it just adds another step for me to parse, when I could have just named it car to begin with.

      That's a simple case where the data being iterated over is clear. When the data is complex, it becomes even more useful to descriptively name i so that you can more easily see what you're working with.

      • eutectic a day ago

        But 'i' is not a car, it is the index of a car.

  • gus_massa 3 days ago

    Why is ii better than i???

    I may understand that instead of x,y it may be better to use px,py for positions and vx,vy for speed. Perhaps xx,xy for position. But I'd never use yy.

    • jmillikin 3 days ago

      I use `ii' and `jj' etc for all my loop counters, because it's easier to search for in any editor.

      Searching for `i' requires learning the local editor's way of marking word boundaries, otherwise it'll highlight every instance of the letter `i' which is useless.

      Searching for `ii' has less noise because very few words have that sequence in them, and `jj' is even rarer.

      • greyfade a day ago

        I would suggest that if you need to search every instance of the variable `i`, your loop is too large and needs to be refactored. Variables like this should only be used in a highly restricted scope that fits on your screen in 36-point font. If the scope is any larger, you need to search, and at that point, you have bugs.

      • arp242 2 days ago

        You can use \bi\b in most regexps. Or \<i\> in Vim (pressing "*" will do that for the word under the cursor).

        This is kind of basic stuff that was around in the 90s, possibly even 80s.

      • throw4950sh06 3 days ago

        You need better tooling. My editor can highlight all references using the type checker.

        • evoke4908 3 days ago

          > Someone shouldn’t have to use source inspection assistive coding tools to parse the code you write

          • ruszki 3 days ago

            This is nonsense. You can parse every code with simple Notepad, if you have time. You don’t need to use even search, if you wish.

            Or you can make your life easier, and use tools which helps you.

            Once again, regardless of codebase.

            • achierius 3 days ago

              "If you have time" is the operative point here. The idea is to make it efficient to quickly search for occurrences.

              So then you get back to the LSP question -- but for larger codebases I can tell you, those don't always work as well as you'd hope. I don't use 'ii' but it's admittedly much easier to just `rg` for variables than hope my editor plugin decides to work today.

              • strken 3 days ago

                In general I agree with you, but in the specific case of loop variables, how much code do you need to search through? How big is your loop if you need to reach for rg to understand it?

        • chaboud 3 days ago

          “You need better tooling” is inconsiderate of others. Sometimes you’re in a browser reading over a CR, or you’re sitting at someone else’s machine, or debugging an emergency via a smartphone.

          Whatever the case, is it really that hard to use a two-letter loop counter? Try it sometime. When building at scale, it just makes sense to be considerate of diversity and do the little things to that make life easier for others.

          • throw4950sh06 2 days ago

            When building at scale, it's not possible to rely on stuff like "everybody should name the iterators differently than it's normally done".

            It's not inconsiderate, we are doing a job. If you can't do your job, you don't have place in my team. And properly using an IDE is definitely part of the job. What are you using that can't open web VSCode that has all these features?

            • chaboud 2 days ago

              There's a big difference between "rely on" and "be considerate of". I'll take from the recently-created throw-away account that you know this already, and, based on this interaction, I don't think I mind not having a place in your team.

              • throw4950sh06 2 days ago

                As a manager of a large engineering organization, I'm unfortunately forced to not be considerate in order to make the org scale to dozens/hundreds of people. Proper usage of tools is crucial and I spend considerable resources to teach the engineers in my org about the tools we use. We took a great deal of effort to make the dev experience full featured, accessible and universal.

                You click a button and get a web browser based IDE where you have everything ready, connected to a cloud computer with a full dev env that mirrors our prod env; that from any branch and the button is right there in pull request UI. There is no reason why someone in this org should require everyone to write double letter iterator var names just because they couldn't be bothered to play the video where I taught how to use the advanced code search and the feature could be available to them in less than a minute of fooling around if they tried.

                On this scale, following standards is absolutely necessary. If my engineer has to stop and think "but wait, in this company they do it differently" - this times 150 people I currently manage - then I failed at my job.

                Some devs hated me when I came into this (much smaller back then) company few years ago and the first step I did was to put a global linter and formatter there. They were angry about how they would format it better than the formatter. Well that's nice - but that doesn't scale to hundreds of people. People make mistakes, stop caring, have different opinions... And all these questions in their minds are again my failure at my job. It's my job to answer these once and forever and to make it easy to follow the rule.

                While this is a personal anecdote, I was a large corporate principal engineer for many years and I am mirroring what I saw working there. I can't say this approach to making software engineering work at scale is uncommon.

                Please note that here I'm talking about working at a job, usually for very good money. Nothing of this applies to personal projects, most open source projects and so on. In these cases I'm very much on your side.

      • jraph 2 days ago

        Many editors can search for whole words.

        Some editors like Kate highlight whole words by just selecting them (and it will not highlight letters in words). Some also do that just by placing the cursor on a word.

      • andoando 2 days ago

        just search for "int i", "let i", etc?

        • pavel_lishin 2 days ago

          That finds the start of the loop, but not occurrences of that index inside the loop.

    • lemonwaterlime 2 days ago

      If you’re doing any kind of scientific computing or electronics computations, “i” or “j” mean the imaginary number sqrt(-1).

      Some software, such as Matlab, have those letters reserved for the common case of imaginary roots of a polynomial, and “ii” and “jj” as variables is a common coding convention. Whether “i” or “j” is your letter for imaginary numbers depends on if you’re an electrical engineer or not.

    • pxx 3 days ago

      I've seen this specific example used to speed up find-next, but it's not like the false positives are frequent enough to bother.

    • card_zero 2 days ago

      I use i for the outer loop and ii for the inner loop, like they're Roman numerals.

  • jbaber 2 days ago

    People mentioning ii instead of i for searchability, then being countered with the sometimes difficulty of searching with word boundaries are missing an important point:

    A variable with big enough scope you'd be searching for it should have a full real name, no i or ii. Even when it's a loop counter, if it's present for more than a page, please tell me what you're counting.

  • leni536 3 days ago

    Optimizing for grep is fair, however searching for whole words is typically possible in most contexts. I don't have a problem for grepping single letter variable names, although I admit that whole word or word boundary search is not as obvious and slightly less convenient than just plain substring search.

    • chaboud 3 days ago

      That’s basically it. Using double-letter loop counters is a very simple courtesy that one can pay to other developers or oneself in the future.

  • cryptonector 2 days ago

    Clearly that rule (no single-letter variables) is pretty dumb. Instead you want something like TFA so that you can easily understand and adhere to the local conventions for such variable names.

dvt 3 days ago

I know this is mostly for Haskell, but I would add (used in various languages):

    e: event
    k: key in hash map, dictionary, etc.
    o: object or reflected object types
    v: value in hash map, dictionary, etc.
    t, u, v, w: vectors (borrowed from math)
Would be fun to think about this for a while and come up with a more serious dictionary with examples and links to code.
  • larodi 3 days ago

    How come are this specific for Haskell and not universal?

    My errors are caught as ‘e’, files are ‘f’, apparently indices are i, j, k, for as long as people been writing C.

    K/V are keys and values, and, well, ‘t’ is time. I’m sure you can guess all other…

    I really don’t understand how is this a specific language’s thing.

    • dvt 3 days ago

      > How come are this specific for Haskell and not universal?

      The author says as much. There's overlap for sure, but all the monad stuff, for one, is mostly Haskell-(or functional language rather)-specific.

    • _jackdk_ 3 days ago

      (Author here.)

      I think the amount of polymorphic code Haskell enables means that single-letter variables are more common than in other languages (where they're usually confined to narrow scopes), and there's a lot less to say about them. Another HN commenter on this post mentioned IEnumerable<T>, which is very similar: you know nothing about T, but you need to call it _something_, and there's a common understanding in the community that you call such type variables <T>.

      Haskell's typeclasses then mean you've got a lot of different concepts that could show up in a type signature, but they're still polymorphic and there's not much you _can_ say beyond "this is Foldable", or "this is a Monad". So an even broader convention has emerged.

      • larodi 2 days ago

        Well apparently because T stands for template or type, but people also use K and P here, all capitals. And again - ‘T’ for type is not unique to C++.

      • Sebb767 2 days ago

        > Another HN commenter on this post mentioned IEnumerable<T>, which is very similar: you know nothing about T, but you need to call it _something_, and there's a common understanding in the community that you call such type variables <T>.

        You know that it's the type you enumerate over. I'd agree that in this case, <T> is sufficiently common language that people understand the reference (similar to how i is understood to be the index counter in a for loop), but you could definitely use a more expressive type name [1]. This becomes important if your type has two or three generic parameters.

        [1] You might argue that this is more typing overhead, but your tooling will easily auto-complete it for you or refactor it after you've written the code, but before committing it. And if you don't have that type of tooling, you're in need of expressive variable names.

    • PaulHoule 3 days ago

      People used I,J,K,L for integers in FORTRAN and BASIC for that matter, in fact early FORTRAN determined the type based on the first letter of the name.

      • kergonath 3 days ago

        GOD is REAL except if declared otherwise :)

    • runeblaze 3 days ago

      Half jokingly if `s, t, a, b` ever becomes universal then either we all ascended to purity heaven or a mass extinction on the scale of K-Pg extinction occurred and wiped out most of earth's programming languages.

  • sph a day ago

    Also r: Reader and w: Writer, especially in languages with such generic interfaces (Rust, Go)

  • jonathrg 3 days ago

    a is for array

    b is for byte or buffer

    c is for character

    d is for destination

    e is for event or error

    f is for file

    g is for graph

    h is for handle

    i is for index

    j is also for index

    k is for key

    l is for length

    m is for mode

    n is for number-of

    o is for object

    p is for part

    q is for queue or query

    r is for reader

    s is for source

    t is for time

    u is for user

    v is for value

    w is for word

    x is for x component

    y is for y component

    z is for z component

    • RheingoldRiver 3 days ago

      A is for Array:

      A is for array, some things in a list

      B is for byte, how computers exist

      C is for character, one letter in a word

      D is for destination, where results are stored

      E is for event, interaction in the DOM

      F is for file, sometimes written to ROM

      G is for graph, some edges and nodes

      H is for handle, it references loads

      I is for index, add 1 as time flies

      J is for index, but different from i's

      K is for key, in associative arrays

      L is for length, as in how many j?

      M is for mode, and not like ice cream

      N is for count, like sheep in a dream

      O is for object, some data and code

      P is for part, to share out the load

      Q is for queue, process one at a time

      R is for reader, I can't think of a rhyme

      S is for source, and you're doing great

      T is for time, 429 makes you wait

      U is for user, like you'll be one day

      V is for value, associated to k

      W is for word, collections of c

      X is for x-component when doing 3D

      Y is for y-component like x is again

      Z is for z-component, we got to the end!

      [note, i am not sure what is meant by P = part, and I know some of these are kind of lame and got worse as I got impatient to finish]

      [i wrote this myself, it is not ai-written]

      • sitkack 2 days ago

        NL is for not for long

    • rphln 3 days ago

      Would've been perfect had you said jndex.

    • _jackdk_ 3 days ago

      Good catch, I'd forgotten "reader" (as in `ReaderT`). Thanks.

__MatrixMan__ 2 days ago

I'd love to see this idea expanded into various branches of math and science and various other languages.

I remember the moment I learned that phi and theta were used by both mathematicians and physicists for rotational components of a spherical coordinates system, but that their roles are switched:

    math: theta=polar phi=azimuthal
    physics: phi=polar theta=azimuthal
It felt like there should be a place for that kind of knowledge. I'm all for violating convention with purpose, but so often we violate convention because we don't know any better. That's just needless complexity.
  • taeric 2 days ago

    Have you gone down the rabbit hole of why the y coordinate is inverted in many computer graphics? :D

    • __MatrixMan__ 2 days ago

      My first programming language was Ti-BASIC where screen coordinates worked with y=0 at the top. A natural choice given how the OS worked. I used it to cheat on math tests, so the two never felt like separate worlds to me and I understood the reason for both.

      As for phi and theta, it just seems so arbitrary.

    • retromagik 2 days ago

      It's because CRT displays draw from top to bottom, right?

      • gweinberg 2 days ago

        I think it's more because printers (used to) print going down. I don;t see why it would matter in the least that crts draw the top first, if that is indeed the case. But for old printers where the paper is continuous, down is "forward" and there is no going back.

        • taeric a day ago

          I think the printers and the old monitors reason are basically the same? Scanlines used to be a "you have now to set this pixel, if you missed it, you get next scan." It is an oddly accurate mental model to think of the screen as printing an image every scan.

      • taeric 2 days ago

        Largely that seems to be the consensus, yes.

phforms 3 days ago

Clojure developers also often make use of single-letter variable names, following conventions in `clojure.core`: https://guide.clojure.style/#idiomatic-names

My rule of thumb is to only use short names in the local scope of a function and have them follow conventions within the language community. Constrained like this, I see no harm in using them, since their meaning is clear within the context of their usage and there is usually no need to search for them. Of course, if the variable has a more specific meaning, I choose a more specific name.

  • actuallyalys 3 days ago

    I had the thought of making one for Clojure. I didn’t realize one already existed, so thanks!

semi-extrinsic 3 days ago

Fortran's implicit typing sends its regards from an IBM 704.

  • microtherion 3 days ago

    Yes, I was thinking of this. Picturing a bastard child of Haskell and Fortran right now, where the type of a variable is determined again by the first letter of its name.

    • sitkack 2 days ago

      Hasktran is a much better name.

Dwedit 3 days ago

C# basically forces "e" to be the name of EventArgs in any event handler. You can change it, but it will always default to "e".

  • ZeroClickOk 3 days ago

    I have a hard time normalizing existing codebases where coders insist on using `catch (Exception e)` instead of the default `catch (Exception ex)` and then there are clashes in event handlers with try/catch due to the same variable name...

  • rerdavies 3 days ago

    Which is a PITA when you have a method that takes some event, e, as an argument.

artemonster 3 days ago

As someone who is used to code in python and typescript explain to me in layman terms why the HELL would you need something like this: "...in lenses or other optics. The simplest complete example is a Lens s t a b: it can extract an a from an s and overwrite it with a b. Doing so would produce a value of type t."

  • pona-a 3 days ago

    Lenses seem to be a functional pattern that groups getters and setters into composable functions.

    Consider pair(a, b) with first(pair) and rest(pair). I can define first-lens and rest-lens for [get-first, set-first] and [get-rest, set-rest] respectively. I could use them as simple getter/setter groupings with lens-view(rest-lens, pair) or lens-set(first-lens, 4, pair), which isn't so useful by itself, or I can compose then to get third-lens with lens-compose(rest-lens, first-lens), allowing me to lens-set(third-lens, 7, pair) without a nested call.

    I just tried to summarize what I could read [1] [2] [3] and I don't claim to entirely understand it, but it's still better than the sibling comment dismissing it as abstract nonsense.

    [1] https://docs.racket-lang.org/lens/lens-intro.html

    [2] https://hackage.haskell.org/package/lenses-0.1.4/docs/Data-L...

    [3] https://theswiftdev.com/lenses-and-prisms-in-swift/

  • rcxdude 3 days ago

    Basically because in languages where everything is immutable, 'setting' a value nested in a datastructure is a big hassle. Lenses give you a means to effectively do foo.bar.x = "baz" succinctly (and a few other bits besides).

  • kqr 3 days ago

    As others pointed out, you don't need any convenience from a modern language.

    But what optics (often sloppily referred to as lenses) give you are really powerful getters and setters. They can do what getters and setters in Python do, but they can also

    - target multiple fields in multiple objects at the same time, or

    - target fields only when a condition is true,

    - they can target deeply nested fields,

    - they can target computed values which have a compound effect on the underlying fields,

    - they can return a new full object where the targeted fields are transformed by an arbitrary function, etc.

    This means optics are extremely broadly useful. They can be used as OO-style getters and setters, but they can also be used to build and navigate JSON objects, or parse HTML content. It's a common interface that can be used for getting and modifying data in any broader context.

  • dmkolobov 3 days ago

    It’s essentially a way to give types to “mutable” views into larger data structures.

    s - the larger data structure

    a - a view value

    b - a “update” value

    t - the data structure after an update is applied

    Of course, everything is still immutable in the same way that cons-ing a value onto a list is immutable.

    The change in type between s and t allows you to nest these views, hide information, etc.

    • _jackdk_ 3 days ago

      You've got the right general idea but the difference between `s` and `t` is not for nesting - you can write a composition operator for a "simple" lens where s=t and a=b.

      `b` and `t` are just for type-changing updates, like when you replace a field in a tuple or every element in a list.

  • kristopolous 3 days ago

    Haskell is by mathematicians and for mathematicians. I know this sounds absurd but many actually find it to be the easiest programming language for them. I've met mathematicians who claim they were not able to code until they found Haskell.

  • cstrahan 3 days ago

    Sure, I can do that.

    Why the HELL would you need objects and object oriented programming? Wherever you do foo.blah(), you could just do foo_class__do_blah(obj)… so what do objects really grant you that you can’t do with basic procedural programming?

    Why do you need Python’s function decorators? You can just manually copy and paste whatever logic you need into each and every function, instead of decorating them.

    Why have an iterator protocol? Every datum can have it’s own bespoke way of iteration that you simply have to memorize on a case by case basis (and can not be abstracted over in any common way), why make everything conform to the same interface?

    Why have anonymous functions that can close over their lexical scope (what people usually refer to as “closures”)? Consider:

      let x = 0;
      let inc = () => x++;
    
    You could just write:

      function inc(bindings) { return bindings.x++; }
    
    And then remember to pass along bindings whenever you need to call inc. Besides, that’s more or less what’s going on behind the scenes.

    I could keep going.

    We have these facilities not because they are essential (go program in assembler, and you’ll see how few programming techniques and concepts your processor actually cares about), but because they are nice to have. They are nice to have because they provide us tools for abstraction, so by solving the general case, you solve a host of concrete cases.

    Lenses let you abstract over data traversal and projection.

    Maybe you don’t appreciate that, and that’s fine. There are C programmers who don’t mind writing 100 different hash tables for different keys and elements. If you are a Python/TS developer, I’m pretty sure you’d find that surprising — if you want a dictionary/hashtable, you just use a dict and call it done — you wouldn’t go build a new dictionary class for each and every key-type/value-type pair.

    Different people have different tolerances for the drudgery of solving the same problem for the 100th time.

    However: while I don’t understand why someone would choose vanilla ice cream if they’re given the option of chocolate, I wouldn’t act flabbergasted in such a scenario. Why would I? Why should I expect my desires to be the same as everyone else’s?

    The only reason I can think of that someone would express shock at someone choosing vanilla over chocolate is if they think that the preference for vanilla indicates something is fundamentally wrong them. Or in other words: being a condescending bigot.

    That’s kinda how you’re coming off.

    In the event that you were actually asking in good faith: if you like to broaden your skills so you can finish programming work faster, I’d recommend reading up on lenses. If you don’t care about that, that’s fine too, but I’d recommend against expressing shock at the fact that others do care about these types of things.

    • _jackdk_ 3 days ago

      I dunno mate, I think GP's a little sharp, but it's great that he asked his question and expressed just how baffled he was instead of closing the tab and going "those Haskellers are a bunch of loonies". But I think you came out swinging here in a way that's not helpful. Accusing GP of bigotry because he didn't understand, and asked a question to understand?!

      I agree with the technical points in your post and disagree with its venom. It's important to notice patterns and abstract over them, and to teach people to spot commonalities they haven't yet noticed in their code. Next time I think you'll have better luck starting with the assumption of good faith and going from there.

    • rcxdude 3 days ago

      To be fair, idiomatic python code almost never has the constraints that would make a lens useful. Python programmers would just mutate their datastructures, or if they are trying not to mutate the original, copy it and then mutate it, or use a closure to represent the access to the nested structure, something that is about as succinct as representing it via lenses in functional languages. That's why it seems kinda unnecessary as a construct to someone who's only used to thinking about coding that way.

  • _jackdk_ 3 days ago

    (Author here.)

    It's a very fair question. I'm pretty sure lenses were invented because Haskell's built-in records are not ergonomic, but then the community discovered that they're extremely useful, general, and flexible.

    Here is a Redux (JS) example of the problem that lenses help solve, where you are working with immutable data and want to replace one field of a deeply-nested structure: https://redux.js.org/usage/structuring-reducers/immutable-up...

    You can think of a lens as a getter/setter, stored together as a first-class value. I'm not great at TS but hopefully you can see what I'm getting at with these types:

    A Lens<S,T,A,B> is a pair of functions:

    * get: (s: S) => A

    * set: (s: S, b: B) => T

    The most obvious lenses you can make are lenses that represent record fields (object properties?). But you can make lenses into other things, like a function that returns a lens into the Nth bit of an integer, or a function that takes a map key and returns a Lens from Map<K,V> to Optional<V>.

    You use lenses by passing them to functions that then operate on your data. Three common ones are `view`, `set`, and `modify`:

    * view: (lens: Lens<S,T,A,B>, s: S) => A

    * set: (lens: Lens<S,T,A,B>, s: S, b: B) => T

    * modify: (lens: Lens<S,T,A,B>, s: S, f: (a: A) => B) => T

    So far, it doesn't look like we've bought much. But the real payoff comes from when you notice that lenses compose:

    * compose: (outer: Lens<S,T,X,Y>, inner: Lens<X,Y,A,B>) => Lens<S,T,A,B>

    This solves the "nested record problem" because you can compose the lenses for each field in the chain to get a lens from the outer structure to the field you're interested in, and functions like `set` and `modify` will correctly copy all the fields at each layer when you call `set` or `modify`. Haskell's lens libraries give you compact operators for doing this, so it all looks neat and tidy.

    A reasonable response to all this machinery is, "OK, your language has bad records and you built a library to paper over them. So what?" To this I say:

    1. Every language has this problem when working with nested immutable data, though not every language has the tools to compactly encode lenses and make them ergonomic to use; and

    2. Lenses generalise to give you other "optics". A `Traversal<S,T,A,B>` picks out zero or more `A`s from `S`, and can replace them all with `B`s. `modify` and `set` then generalise, and perform their update on _every_ matching `A` selected by the `Traversal`, and you also get `toListOf`, which collects all matching `A`s into a list. There are other optics too, but this post is getting long.

    Once you have the more powerful optics, you get a very expressive toolkit for querying and updating data, that works on any data structure that has optics defined. (And Haskell has tools to derive many optics automatically.)

    Chris Penner's wonderful book, _Optics By Example_[1], has a bunch of exercises that involve slicing and dicing a big slab of Kubernetes YAML with queries like "collect a list of all 'containerPort's alongside their Pod's 'name' (from 'metadata')" and operations like "set a resource request of `memory: "256M"` for every container". The answers are extremely compact and elegant, and I don't know how you'd achieve anything similar with other methods.

    I hope this helped, because there is definitely a really useful and powerful toolkit hiding behind that absurd-looking type signature.

    [1]: https://leanpub.com/optics-by-example/

yawnxyz 3 days ago

js land:

   $: jQuery
   _: lodash, underscore libraries
   e: usually events like keyboard, button clicks, form submits, when preventing form actions...
any other js quirks?
hi-v-rocknroll 2 days ago

While some people argue for verbose, semantic-meaning variable and function names, I believe taking this to the extreme is counterproductive, especially for internal code that could otherwise be far more terse. Like antipatterns in Java, C++, or Rust, the more stuff there is at a lower density on the screen, the harder it is to follow. For internal bits, single letter variables should be favored.

w10-1 3 days ago

I agree with the semantics, but restrict usage to the very narrow case where the variable has no other use than to convey a value from a visible outer scope to a visible inner scope, where both together are less than a few lines. In that case I prefer the single character over a longer name precisely because it is clearer.

Note that x,y,z don’t really qualify as abbreviations since they are the full name of the component, so they can be used when the outer scope is not visible — eg as a parameter.

durumu 2 days ago

IMO using a lowercase l as a numeric variable is cursed. It is way too easy to read it as 1 in many monospace fonts.

  • sitkack 2 days ago

    I totally agree. Maybe a font with boxes around the numbers? Or some other way to disambiguate them.

    • rozab 2 days ago

      Perhaps some sort of system could be implemented to cause the teleprinter to use a different variety of ink, depending on the nature and syntactic context of the symbol

      • sitkack a day ago

        I like this, for bold it could backup and hit that char again.

    • gsck a day ago

      Or just get a font that draws the i with a line and a dot correctly, and a 1 with the horizontal line at the bottom and the half width line at an angle at the top.

      You are using a bad font.

johnea 2 days ago

Single letter names? hmm...

Didn't they make a song about that?

a, b, c, d... e, f, g...

Something like that?

t-3 5 days ago

I like to use 'n' as an index when decrementing the counter.

o11c 3 days ago

Edit: I'm trying to merge in all the ones other people have added; most are original still though.

I don't Haskell, thankfully, but a lot of these are applicable broadly. Some notes/additions I've seen in other languages (but far more often these are obvious).

(only vaguely sorted, since many aren't contiguous):

  a can mean "argument" particularly; also "arg"
  a,b,c,d can be anything, but slightly more common for floats and/or coefficients, or matrices
  a is often "array"
  a can be ascii (either as string in general, or in specific)
  a can be "allocator" or "allocation"
  b for bytes is not shameful, but sometimes it means "buffer", "blob", or "bits" instead. Can be used for just an element or for a sequence of them.
  b can be "builder" (a utility class used to construct values instead of using "new" directly)
  b can be "base"
  b,e for begin/end (often for iterators/indices)
  c is often used for "character", "code unit", "codepoint"; ch/cu/cp can disambiguate
  c can also be "constant" (either a value or a modified type)
  c can also be "container"
  c can also be "condition" (a boolean)
  c can also be "context", but more often ctx or ctxt
  d is rarely used for "data", but more often it's expanded or v is used instead
  d can be "direction", but more often dir
  d,s can be destination/source
  e can also be "event"; ev if needed
  e can also be "element" (member of an array, member of an XML-like tree)
  f is common for floats (even if called "double" or "real") or fixed-point numbers
  f is often file; fp/fo may be common depending on the language
  g for graph
  h for handle
  i can also be "instruction"
  i,o,r,w can be input/output
  i,j,k are common as indices *or* iterators, corresponding to x, y, z if meaningful.
  l is rare but can be a 4th index or iterator if needed, usually does not related to w though.
  l is probably more common as "length"/"limit"
  l can be "long" in various senses
  l,h can be low/high, but more often lo/hi
  l,r can be left,right (also lhs,rhs), especially of a binary operator (or occasionally a unary one, e.g. to disambiguate prefix/suffix)
  m = mode?
  n,+m are often specifically the upper bound of a range, similar to l
  n can be node (of a tree/graph)
  o is an arbitrary object (usually, when explicitly not a primitive or string)
  o can be "origin"
  p,+q are not rare as "predicate"
  p,q can also be prime numbers
  p is for pointer
  p = part?
  p,q = percent chance (often normalized to 0-1 though)
  q for queue
  q for query/request
  q for "quad"
  q,r,n,d for fractions
  r (and rv/res) is sometimes used ambiguously - should it be the return value of a function I called, or the value I'm planning to return? Can also stand for "reply".
  r can be "range"
  r can be "rectangle"
  r can be "register"
  r,c for row, column; origin is top-left and axes are flipped
  r,g,b,a are color components; other letters exist for other colorspaces
  s is often an arbitrary string
  s can also be symbol (sy/sym depending on context), statement (stmt), or set (often given a different kind of name)
  s can be "stack"
  t for table
  t for time
  t,u,v (usually uppercase) are arbitrary types in generics
  u,g,o for user/group/other
  v is often just an arbitrary data value (not meaningfully numeric/string/object), even without a container
  v,w,t,u can also mean "vector" specifically
  w = word
  u,v,s,t,q are used for 2D texturing
  u can be unicode
  w can be wide character, but good riddance
  w is for window
  x can also be "expression" in particular
  x,o,d,b can be hex, octal, decimal, or binary bases
  x,y,w,h are start/size of a rectangle
  x,y,z,w are used for 3D objects; w is often normalized to 1
  _ as a function or string affix means "call gettext on this now"; N_ means "remember to call it later"
  _,$ are sometimes injected as a general-utility global variable in languages with deficient standard libraries
Mostly not mentioned, several of these are used uppercase for generic type arguments.

I'm also ignoring all the various units and physical constants.

I'm pretty sure about a dozen more passed through my head while writing this but I forgot them before I finished writing the previous entry, and I can't be bothered to actually start scanning code.

  • archargelod 3 days ago

      b for boolean
      d for distance / date
      e for error / exception
      f,g are often used as generic function name
      g can be global value
      r for radius
      r is a random value
      t for tally
      t is any temporary value
      m for matrix
    • o11c 3 days ago

      Hm, I probably should pull out the ones from the original article that I actually recognize (a couple of yours are from that). Mine was originally intended as a supplement, then it got out of control.

      I thought about `M` for matrix but after thinking I realized it's almost always `A` or something, with `m` as a dimension. That does remind me of `I` for identity though ...

      Ah, the editing window is closed, so I guess I have to extend it:

        f,g,h - function
        f - flags
        i - identity (e.g. of matrix)
        h,n/p,m - haystack, needle/pattern, match
        h,t - head, tail
        k,v - key, value of a map/dictionary
        l - location
        s - state
        t - token
  • Supermancho 2 days ago

    > _,$ are sometimes injected as a general-utility global variable in languages with deficient standard libraries

    I would say that underscore is used as convention. There are languages where the underscore is either tool supported or language reserved for this purpose broadly or in limited context (lambdas). Languages that use underscore for ignored values include Java, Erlang, Python, Scala, Clojure, F#, SML, Swift, et al.

    • aloisdg 2 days ago

      True in Elixir too

vips7L 3 days ago

Part of the reason why Haskell never took off. This stuff is incomprehensible.

  • dmkolobov 3 days ago

    I know this is a troll comment, but the situations you see these variables are in highly-polymorphic( generic ) code in which there are no more descriptive names.

    It’s like the use of `T` as a name in most Java or C++ generics.

    • yCombLinks 3 days ago

      I don't see it as a troll comment

  • broodbucket 3 days ago

    This stuff is utterly incomprehensible to me as well, but I don't think Haskell is trying to be a mainstream use-it-for-everything language. It does get plenty of real-world usage and the people who like it really like it, so for a language so complicated to get as much use as it does sounds like it "took off" perfectly fine