1. 44
  1. 6

    I mean, what human can interpret *++argv?!

    I now believe the reason is fairly simple: in essence, OpenBSD’s style squeezes more code onto the screen.

    I don’t see how one can come to such a conclusion based on the echo source code shown as an example: there are blank lines separating logically related lines of code, the variable name (nflag) could have easily been called just n or perhaps nf (n is traditionally used for size/length/count), etc. Overall, I found the code quite easy to follow and there is definitely much denser code out there where you will hardly see a blank line.

    But I think the first quote hints at the real reason (IMO, anyway): the example is easy to follow because it doesn’t shy away from idioms that pack a lot of meaning into very little code.

    1. 1

      J/APL, and their inspired golfing languages come to mind when thinking of the upper limits of terseness.

      1. 9

        I was researching array languages recently and came across this interesting quote in the README of an open-source K implementation:

        A note on the unusual style of C code: It attempts to replicate the style of Arthur Whitney. A striking original example is contained in file https://github.com/tavmem/buddy/blob/master/a/b.c. There are 2 versions of the buddy memory allocation system. The first is in 11 lines written by Whitney. The second is in well documented traditional C (almost 750 lines).

        The example is, indeed, striking.

        I MZ[31]={1};Z I *MM[31];mi(){MZ[7]=MZ[13]=MZ[19]=MZ[25]=2;DO(30,MZ[i+1]+=MZ[i]*2)}
        Z mmr(n,i){if(i<18)i=18;R err(2,n),tmp((MZ[i]+2)<<2),1;} /* Dan MZ[i+1]? */
        C *mab(m)unsigned m;{I *p,*r,i=2,n=m;for(n=(n+3)>>4;n;n>>=1)++i;
         do{if(p=MM[i])R MM[i]=(I*)*p,(C*)p;for(n=i;n<30;)if(p=MM[++n]){
          for(MM[n]=(I*)*p,p[-1]=i;i<n;)r=p+MZ[--n],MM[r[-1]=n]=r,*r=0;R(C*)p;}
          if(mc()>=i)continue;} while(mmr(m,i));}
        I *ma(m){R(I*)mab(m<<2);}
        mf(p)I *p;{I i=p[-1];*p=(I)MM[i],MM[i]=p;}
        mb(p,n)I *p;{I i=31,j;for(n-=2,++p;i--;)if(j=MZ[i],j<=n)n-=j,*p=i,mf(p+1),p+=j;}
        mc(){R 0;}
        I *mz(){Z I b[31];I *p;DO(31,for(b[i]=0,p=MM[i];p;p=(I*)*p)++b[i])R b;}
        

        Although the rest of the code – the Whitney-inspired code – is equally baffling to my eyes.

        I suppose that, in order to invent or implement K, you have to place a pretty high value on terseness.

        1. 3

          This is a rather famous block of code, but each time I see it I feel further away from any precise conclusions about it. It seems clear that the authors of J/K/etc. are comfortable with this style and our ability or inability to read it is pretty irrelevant since we’re not likely to find ourselves maintaining it or patching it.

          The whole APL family sets up different priorities than the rest of computing. For instance they like “idioms” more than functional abstraction, because apparently it’s both difficult to name some of the idioms in a useful way, and when you do, the name tends to be larger than the idiom itself. Also, at least J (but I believe most APL family languages) makes liberal use of “special code” that notices certain idioms and has optimized code to handle those cases.

          I have come to see it as a completely different coding “civilization,” and I won’t pass judgement on it because I have seen how much work it would take to reorient myself to it, and I just won’t ever find the time to do so.

          1. 1

            Most programming languages have idioms. And apl does not lack functional abstractions. Special code seems rather similar to the open-coded algorithms based on simple graphical pattern matching which can be found in most compilers.

        2. 3

          I came in to say….

          Gradually I started to realise that not only could I cope with OpenBSD’s terse code style, but it was actually easier for me to read it than code I’d written myself.

          If you want the best teacher for this lesson, learn APL or J or K or BQN, and keep learning until that code no longer seems dense, but simply “just the right amount to express what I want”.

      2. 6

        In recent years, the new generation of programmers, was taught to avoid terseness with all costs. If the BSD code would be commited inside the companies I’ve worked for, the PR will be immediately rejected by the Team Leads, as it doesn’t follow their inner representation of what clean code is.

        Also I am connected to various programming communities, either on discord, Reddit, and some smaller forums, and without overgeneralising, the moment someone writes what is considered to be “terse” code, she/he is instantly called for.

        It’s an empirical observation.

        Personally, when I’ve first started to program I was hunting for onliners and what I’ve considered to be cleverness. Then, after being almost îndoctrinated with various clean code principles, I’ve went to the other extreme, being overzealous in making everything obvious to the potential readers.

        Now I’ve started to appreciate terseness more. Who knows what the future holds.

        Thanks for article. It was a nice read.

        1. 6

          Overly terse code is one thing, and should definitely be rejected in code review, but a good grasp of idioms is essential to writing (and reading/reviewing) good code. I think it’s fine to use idioms that seem terse at first (like that *++argv) as long as you don’t use short names for long-lived or contextually important variables.

          I think I’ve rejected some idiomatic code I didn’t understand in a language I was new to. That’s why it’s a good idea to have the more experienced developers do the reviews, or have the more experienced developers making the PRs but pushing back on initial rejections, explaining how code is idiomatic, to come to a shared vocabulary of idioms.

        2. 4

          Postgres, the Go standard library and - parts of - the kubernetes codebases have served similar purposes for me. Not necessarily as terse as your style example, but similarly showcasing how comprehensibly something can be expressed if you don’t get yourself lost in abstractions and indirections.

          1. 4

            I think most of us give the language more credit because most of us do not get exposed to a large amount of code in very different codebases. We should do more reading (Diomidis Spinellis had a book about this topic called Code Reading) but most of us only read the codebases we’re paid to write and maintain, plus whatever was part of the language tutorials we took. As a profession, we don’t think of ourselves as readers, or do as much reading as we should.

            1. 3

              In terms of low-level style, K&R was a big influence, and Smalltalk-80 was another, although they’re quite different. ST is much more English-like but both of them end up fairly terse.

              The Smalltalk environment made it easy to browse the source code of every class and method in the system, all the way down to Integer and False. It was a great lesson in OO design.

              1. 5

                I mostly agree on Smalltalk but, learning Smalltalk after Objective-C, I was made aware of quite how much effort the folks that worked on OpenStep put into naming things. I could usually guess the name of an Objective-C class or method from OpenStep but I did not find the same true for the Smalltalk-80 class libraries.

                OpenStep was the thing that really taught me the value of consistent naming schemes.

              2. 1

                I suppose, if there is one core influence on me, it’s Envelop Basic: I never understood the language very well when I was writing it, but I definitely picked up an attitude of “however I can get something to work” from abusing UI controls to make a video game, even though that was not their intended purpose.

                Which means that I don’t a lot of misgivings about doing non-standard things, if it feels called for by the constraints of the project I’m working on. This attitude has lead me to do things like adding string-join to SQL Server via .NET code, or writing a project in Ruby in Sequel and Sinatra instead of Rails, or building a .NET server/client on web sockets, where the server was intended to make the client easier to test/validate against another service.

                It also means that I read widely, so as to add to my bag of tricks that I can reference when I hit a tricky situation.

                The counter-balance to this is that because I like reading code, I also want to write code that other people like to read, which has also been a long-running influence in how I write code, and it helps me try to avoid treating any particular bit of code as Sacred or Precious, and means that I don’t do non-standard things in shared projects without a reason.

                1. 3

                  … I don’t do non-standard things in shared projects without a reason.

                  This is the key, for me. Do whatever you want in side projects or toys, or even “real” code that only you will ever need to maintain. But if there’s a good chance other people will need to be involved, make “boring” choices. This was a hard lesson for me to learn, personally, so I understand why some people recoil a bit, but it’s important.

                  1. 2

                    I will say, I do think it’s useful to be able to go off the beaten path when it’s called for. It can be a bit of strong leverage, or help you sort out messes that other folks have gotten themselves into.

                    1. 2

                      I think it’s useful to have confidence that you could, if you had to, go and do something complicated and weird. The confidence permits you to go ahead with a straightforward implementation without any hedging in case it’s not “fast enough”. That often runs plenty fast on the first try anyway.

                      1. 2

                        I agree. Granted, to do that, you have to try and do complicated/weird things. I’ve done done both as part of work and as part of hobby stuff. For work, I try to only do it where there seems to be much to gain by doing so.

                        For hobby stuff, I work almost exclusively in niche tech, mostly to keep stuff interesting.

                        I saw a suggestion that developers should be given some room to play outside of production, because if you don’t, they’ll play inside production. And, for me, I took that as a mandate to try strange/different things on my own time, and to generally not do them in prod without a good reason.

                        And, now that I’ve been that for many years, a lot of stuff I’d have had questions about some years ago seems relatively standard. When you’ve written in non-standard programming paradigm (stack-based was this for me), more standard paradigms seem tame and easy to follow by comparison.

                2. 1

                  Nice timing – I’m going through this experience right now while hacking on QBE. Who knew you could write

                  if (condition_1)
                  if (!condition_2 && condition_3 && foo != bar) {
                      // snip
                  }
                  

                  The first time I encountered code like that, my brain immediately went “agh! bad indentation! and no braces!” but now I feel like it’s genuinely easier to read than a chain of &&’s.

                  1. 2

                    What’s the rationale for grouping the first/second set of && though? It looks a bit arbitrary to have if (condition1 && condition2) if (condition3 && condition4 && condition5) (where the condition5 is on a new line even!) instead of grouping them all together.

                    1. 1

                      condition_1 and condition_1 is typically some overshadowing condition, like a value being a certain type while the other conditions are “smaller” conditions, like checking if that value is in some range, etc. Of course, it’s all rather subjective.

                      1. 1

                        Ah, that makes sense, thanks! (I don’t know the details of QBE so for me it all looks the same )

                    2. 1

                      Isn’t this how we got the “goto fail”?

                    3. 1

                      Personally, I found Reginald Braithwaite’s video on Javascript combinators very influential. I appreciate how you can build up a little DSL with tiny, orthogonal functions. I just wish more languages could optimize across function calls better. I occasionally go back to regain inspiration.

                      https://youtu.be/3t75HPU2c44

                      1. 5

                        The combinators style of programming comes from functional programming. You’ll find that production-ready implementations of functional language implementations (Haskell, Scheme, OCaml) are typically better optimized for this style.

                        1. 1

                          Yeah, it’s just unfortunate that the languages I use for work don’t really support the style that I enjoy.