Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

Code Readability for "Higher" Level Languages

  1. May 27, 2015 #1

    Zondrina

    User Avatar
    Homework Helper

    There really is no specific guideline for this. Personally, I like to write my code as compact as I can, but is there really a problem with this? Having those small complicated statements can make code hard to read, but is that not up to the developer's/reader's level of skill?

    For example, the following is a piece of code written in java (A language I'm sure most programmers are familiar with, so I'll use it for this example). It is written inside a Seat class where there is a private field called 'booked' of type boolean. It should be fairly clear what this code segment accomplishes:

    Code (Text):

      /**
      * If this seat is available, books it and returns true.
      * If the seat is not available, returns false.
      *
      * @return boolean: True if the seat was successfully booked, false otherwise.
      */
      public boolean book(){
        if(!booked){
            booked = true;
            return true;
        }
        return false;
      }
     
    Below is a piece of code which accomplishes exactly the same thing. Although you will notice the syntax is significantly different:

    Code (Text):

      /**
      * If this seat is available, books it and returns true.
      * If the seat is not available, returns false.
      *
      * @return boolean: True if the seat was successfully booked, false otherwise.
      */
      public boolean book(){
          return !booked ? booked = !booked : false;
      }
     
    Many will claim the second piece of code is hard to read, and they would prefer the first version.

    Is there really a disadvantage to writing code like in the second code block? I think it might be coder's apathy if anything.

    More importantly, are there actual advantages to writing code so compactly? Does it influence the run-time in any fashion? Does it have other benefits?

    When is code readability actually a factor? If you are working with software professionals, I'm sure they would be able to read both versions anyway.

    What are your opinions?
     
  2. jcsd
  3. May 27, 2015 #2

    Mark44

    Staff: Mentor

    An excellent resource is "Code Complete" by Steve McConnell.
    Absolutely there is. First, why do you think there is an advantage in writing "compact" code? The "compact" that you refer to is the density of the source code, which is only loosely related to how compact the object code/executable is. Second, writing compact (or terse) code obscures the meaning, which makes it much more difficult for a programming, even yourself after several months, to ascertain what the code is doing.
    A given piece of code can live on for many years after it is initially written (see Software Life-cycle). The original developer is often not the same person who wrote the code. Even worse, the original developer very likely was too clever by half in making the code inscrutable, which caused bugs to appear. By writing dense, inscrutable code, the "clever" programmer is making the maintenance programmer's job much more difficult, possibly causing additional bugs to appear, due to the maintenance programmer's changes to fix the original programmer's bugs.
    Slightly different? I don't think so. The code in the first example is clear. You would have to work extra hard to make the code in the second example less clear.
    Most of the time, nol
    It's quite possible that the compiler will produce the same object code in both cases.
    Most, if not all of the time.
    There is not a single level of software developers. One of the most important attributes of a software developer is to write code that can be easily understood by humans. Virtually all code that is produced by humans has faults in it, and writing "clever" code makes it more difficult for others to find and fix those bugs.
     
  4. May 27, 2015 #3

    Zondrina

    User Avatar
    Homework Helper

    Never too hard.

    I feel as if coding classes are trying to teach you to be maintenance programmers. It's almost as if the clever solution is actually wrong.
     
  5. May 27, 2015 #4

    Mark44

    Staff: Mentor

    In some respects, an overly clever solution is wrong. To clarify what I mean, if a section of terse, impenetrable code makes it difficult to make changes to that code, and increases the probability of more bugs, this could convince customers to look for a different software provider.

    If you don't have the McConnell book I cited, and you have aspirations to write code, get it.
     
  6. May 27, 2015 #5

    Merlin3189

    User Avatar
    Gold Member

    Yes. No. No. No. Whenever code is read. Always write for clarity and avoidance of possible errors, except when replying to questions like this.
     
  7. May 27, 2015 #6

    Merlin3189

    User Avatar
    Gold Member

    What makes obscure code "clever"? Sometimes clever code is obscure, but turbidity or obscurity does not make it clever.

    In your example there is a simple straightforward way of doing the job. What is clever about rewriting it in a less obvious way? As Mark said, it will probably result in the same object code.

    I think you have to ask yourself, why you are writing the code. Are you trying to show how clever you are, or are you trying to write code that works? If the former, your clever code may be better, but if the latter, then the original code is better by far.

    As for maintenance programming, try it sometime if you think you're good enough. Anyone can write their own code, but it is not so easy to modify someone else's.
     
  8. May 27, 2015 #7

    FactChecker

    User Avatar
    Science Advisor
    Gold Member

    One place where the compact form is better is where there are several similar, simple lines that can be put one after the other. Then it is easier to see the similarities and the differences from one line to the next. Your examples should not disturb anyone, but some people go crazy with conditions nested within conditions, within conditions. You would be surprised. I think that many coding standards are there to stop people like that.

    Regarding speed: An optimizing compiler will probably create the same series of operations from both types of code. No speed difference.
     
    Last edited: May 27, 2015
  9. May 27, 2015 #8

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    Considering that the programmer who is assigned to maintain your code may well be a homicidal maniac who knows where you live (those are not my words), yes, there really is a disadvantage to writing code like you wrote in the second code block.

    In a more serious nature, you certainly aren't going to write booking software like either of the two code blocks. What if users X and Y try to simultaneously book the same seat? I've been on flights where my boarding pass and another person's boarding pass had us sitting in the same seat. The mess that ensues can indeed turn one into a homicidal maniac hellbent on finding where the stupid programmer for that double booking lives.

    In real life, you may well need to do a lot more than using the ternary operator to perform tricky little bit of logic. Don't be tricky. That other logic (which is essential) is complex enough to give a maintenance programmer headaches. Don't add non-essential headaches to the essential headaches that cannot be avoided.

    Tricky code is not only hard for another human to understand, it's also hard for a compiler to understand. Your tricky tricks may well be suboptimal as far as performance is concerned.

    I fully understand the appeal of the ternary operator. Deep in the core of me, there lurks an FP (functional programming) mindset. The ternary operator appeals to that mindset. I also know that most people (and that includes some otherwise very good programmers) are deeply confused with overly complex boolean logic (guilty), the ternary operator (guilty again), the comma operator (guilty yet again), and extended regular expressions that are over 100 lines long (also guilty!).


    I wrote the programming standards for multiple projects at NASA. In almost all of them, I authored some 'anti-DH' rules that forbade the use of the ternary operator and comma operator. When asked why, I had plenty of code golfing code to show them (some written by me) that demonstrated why that rule was a good idea.
     
  10. May 27, 2015 #9

    FactChecker

    User Avatar
    Science Advisor
    Gold Member

    Agree. Baby steps are best. It is better to divide a complicated expression into smaller logical parts and steps. It does not slow the computer down. It always seems to be the part that you trusted the most that has a bug. And it is always easier to spot a bug when it stands alone in a simple operation. If a bug is buried in a complicated expression, good luck.
     
  11. May 27, 2015 #10

    nsaspook

    User Avatar
    Science Advisor

    DH, Bravo... When I see code like this it makes me think someone wants to make their code unreadable for job security.o0)

    Tricks are for kids.
     
  12. May 28, 2015 #11

    SteamKing

    User Avatar
    Staff Emeritus
    Science Advisor
    Homework Helper

  13. May 28, 2015 #12

    Mark44

    Staff: Mentor

    Here's an entry from the International Obfuscated C Code Contest, from the 2012 contest.
    Code (C):
    #include<stdio.h>
    #include<stdlib.h>
    #include<ctype.h>
    int u,z,q[0400],O[0x101],o[0401],I[257],w[258][0403],W[0x100],Z[0x103],c[0403],k
    ,i,j,n,l,p,m;const char*J[0416],*M[0400];FILE*K[280],*s[0x102];void f(char*n,int
    a){char*e=n;while(*e!='\0'){if(tolower((int)*e)!=*e)fputc(040,stderr);fputc((*e)
    -a,stderr);e+=1;}(void)fputc('\n',stderr);}int y(int a,int b);int t(int i,int j)
    {int k=i&j,l=i^j,n,m=1;for(n=1;k>=n;n<<=1)if(k&n)m=y(m,1<<n|1<<(n-1));return m>1
    ?y(m,1<<l):1<<l;}inty(inta,intb){intn,i=0x0,j;if((n=w[a][b]))returnn;for(;a
    >>i;++i)for(j=0x0;b>>j;j++)if(((a>>i)&1)&&((b>>j)&1))n^=t(i,j);return w[a][b]=w[
    b][a]=n;}void a(void){for(i=0;i<z;i++){n=0;if(!i[I]){for(j=0;j<u;++j)if(i[O]==q[
    j])n=Z[j];}else for(j=0;j<u;j++)n^=w[Z[j]][w[I[i]][W[w[o[j]][O[i]^q[j]]]]];c[i]=
    n;}}void X(int v,int u){char*y=0;v-=1;switch(v){case(0x2):y="HckngfVqQrgpKprwv"
    "Hkng"; BC(4):y="JempihXsStirMrtyxJmpi"; BC(0):y="PointValueTooLarge"; BC 0x1:y=
    "EvqmjdbufJoqvuQpjou";BC(6):y="TuOtv{zLorky";BC(3):y="WrrPdq|RxwsxwSrlqwv";BC(5)
    :y="GfiFwlzrjsyX~syf}"; BC(07):y="UvV|{w|{Mpslz";}if(u)exit(0); f(y,v);exit(1);}
    int main(intt,constchar*T[]){for(i=00;i<0x100;++i)for(j=0;j<=i;++j)if(1==y(i,j
    ))W[i]=j,W[j]=i;for(k=0x1;k<t;k++){p=0;for(l=0;(T[k][l]>=toupper('0'))&&(T[k][l]
    <=tolower('9'));l++){p=p*10+(T[k][l]-'0');if(p>=256)X(1,0);}if(T[k][l]=='-'){for
    (m=0;m<u;m++)if(q[m]==p)X(2,0);q[u]=p;J[u]=T[k]+l+1;K[u]=fopen(J[u],"r");if(!u[K
    ])X(3,0);u++;}elseif(T[k][l]=='+'){if(z>=256)X(4,0); O[z]=p;M[z]=T[k]+l+1;s[z]=
    fopen(M[z],"w");if(!s[z])X(5,0);z++;}else X(6,0);}if(!(u!=0))X(7,0);if(!(z!= 0))
    X(8,0);for(i=0;i<u;i++){n=1;for(j=0;j<u;j+=1)if(j!=i)n=w[n][q[i]^q[j]];o[i]=n;}
    for(i=0;i<z;i++){n=1;for(j=0;j<u;j++)n=w[n][O[i]^q[j]];I[i]=n;}while(!(0)){for(k
    =0;k<u;k++){intn;n=getc(K[k]);if(n==EOF)X(42,1);Z[k]=n;}a();for(k=0;k<z;k++)(
    void)putc(c[k],s[k]);}X(11,1);}
     
  14. May 28, 2015 #13

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    That code is broken. Here's a link to the correct version: http://www.ioccc.org/2012/grothe/grothe.c.

    Note that you have to compile with '-DBC=break;case' .

    Here's another IOCCC entry, from 2011. It won "best self documenting program".
    Code (C):
    #define clear 1;if(c>=11){c=0;sscanf(_,"%lf%c",&r,&c);while(*++_-c);}\
      else if(argc>=4&&!main(4-(*_++=='('),argv))_++;g:c+=

    #define puts(d,e) return 0;}{double a;int b;char c=(argc<4?d)&15;\
      b=(*_%__LINE__+7)%9*(3*e>>c&1);c+=

    #define I(d) (r);if(argc<4&&*#d==*_){a=r;r=usage?r*a:r+a;goto g;}c=c
    #define return if(argc==2)printf("%f\n",r);return argc>=4+
    #define usage main(4-__LINE__/26,argv)
    #define calculator *_*(int)
    #define l (r);r=--b?r:
    #define _ argv[1]
    #define x

    double r;
    int main(int argc,char** argv){
      if(argc<2){
        puts(
          usage: calculator 11/26+222/31
          +~~~~~~~~~~~~~~~~~~~~~~~~calculator-\
          !                          7.584,367 )
          +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
          ! clear ! 0 ||l   -x  l   tan  I (/) |
          +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
          ! 1 | 2 | 3 ||l  1/x  l   cos  I (*) |
          +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
          ! 4 | 5 | 6 ||l  exp  l  sqrt  I (+) |
          +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
          ! 7 | 8 | 9 ||l  sin  l   log  I (-) |
          +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(0
        );
      }
      return 0;
    }

    Even python is obfuscatable. Runs on a command line interpreter with a unix-like OS. Want a prettier picture? Just embiggen your terminal window.
    Code (Python):
    from os import popen
    from functools import reduce
    t=['pu'.join(['t']*2)]+[x.join(list(' s'))for x in('col','line')];print((lambda
    Ru,Ro,Iu,Io,IM,Sx,Sy: reduce (lambda x,y:x+y,map(lambda y,Iu=Iu,Io=Io,Ru=Ru,Ro=
    Ro,Sy=Sy,L=lambda yc,Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,i=IM,Sx=Sx,Sy=Sy:reduce(lambda x,y
    : x+y,map (lambda x,xc=Ru, yc=yc,Ru =Ru,Ro=Ro,i=i,Sx=Sx,F=lambda xc,yc,x,y,k,f=
    lambda xc,yc,x,y,k,f:(k<=0)or(x*x+y*y>=4.0)or 1+f(xc,yc,x*x-y*y+xc,2.0*x*y+yc,k
    -1,f):f(xc,yc,x,y,k,f):chr(64+F(Ru+x*(Ro-Ru)/Sx,yc,0,0,i)),range(Sx))):L(Iu+y*(
    Io-Iu)/Sy),range(Sy))))(-2.1,0.7,-1.2, 1.2,30,int(popen(t[0]+t[1]).read()),int(
    popen(t[0]+t[2]).read())))
     
  15. May 28, 2015 #14
    I feel code 1 is more redable. Any one can understand from new starter to experienced person. And as some mentioned compiler will produce same byte code for both.
    There is another aspect to this. We are talking about private data member. Private data member should always have geter and /or setter with required visibility.Once you have setter, it must be used to set the value of private data member. If you follow this principle, code 1 is more suitable and readable.
    So my vote goes to Code #1.
    Remember: Code need not be compact but must be easy to understand, to everyone.
     
  16. May 28, 2015 #15
    The compiler will most likely produce the same machine code for both sets of code. The only difference between using an if statement and a ternary operator is that you can give the compiler some hints:

    Code (Text):
    if (__LIKELY__(x == 1)){
       //Most common case
    } else {
       //Other case
    }
    Usually the only time you care about things like that are supercomputers and kernel code.
     
  17. May 28, 2015 #16

    nsaspook

    User Avatar
    Science Advisor

    There are coding standards even in kernel code.
    Linux:
    https://www.kernel.org/doc/Documentation/CodingStyle
     
    Last edited: May 28, 2015
  18. May 28, 2015 #17
  19. May 28, 2015 #18

    nsaspook

    User Avatar
    Science Advisor

    Optimizing branching and memory access is complex (a necessary requirement for good kernel code) , writing it with tricky functions just makes it complicated.
    https://www.englishforums.com/English/ComplexComplicated/dqrvk/post.htm
     
  20. May 28, 2015 #19

    Zondrina

    User Avatar
    Homework Helper

    That link to the CPU memory article was quite interesting, thank you for sharing. Page 57 was quite insightful on its own:

    I wonder why they simply don't depreciate things if they don't want people using them. Although the ternary operator does have some usage in deciding what to print.
     
  21. May 28, 2015 #20

    rcgldr

    User Avatar
    Homework Helper

    What is considered to be a high level language these days? In the past, C / C++ were considered as medium level languages.

    One example of a high level language, but with difficult readability is APL, where it's common to write compact code, and the language features single greek letter operators, and strict rules for order of evaluation. Sometimes jokingly called a write only language since no one can read it. Wiki link:

    http://en.wikipedia.org/wiki/APL_(programming_language)

    Take a look at the game of life example. Here's a video explaining an alternate version:

     
    Last edited: May 28, 2015
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook