Code Readability for "Higher" Level Languages

  • Thread starter STEMucator
  • Start date
  • Tags
    Code
In summary: Compacting code may seem like a time-saving technique, but it can actually cause more problems in the long run. It can make code harder to understand and maintain, and can also lead to bugs and errors. Writing clear and readable code is important for all developers, regardless of their level of skill. It may take a bit more effort, but it ultimately results in more efficient and effective code.
  • #1
STEMucator
Homework Helper
2,076
140
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:
  /**
  * 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:
  /**
  * 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?
 
Technology news on Phys.org
  • #2
Zondrina said:
There really is no specific guideline for this.
An excellent resource is "Code Complete" by Steve McConnell.
Zondrina said:
Personally, I like to write my code as compact as I can, but is there really a problem with this?
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.
Zondrina said:
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?
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.
Zondrina said:
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:
  /**
  * 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:
  /**
  * 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 : !booked;
  }
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.
Zondrina said:
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?
Most of the time, nol
Zondrina said:
Does it influence the run-time in any fashion?
It's quite possible that the compiler will produce the same object code in both cases.
Zondrina said:
Does it have other benefits?

When is code readability actually a factor?
Most, if not all of the time.
Zondrina said:
If you are working with software professionals, I'm sure they would be able to read both versions anyway.
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.
Zondrina said:
What are your opinions?
 
  • Like
Likes seastryder, jim mcnamara and Merlin3189
  • #3
You would have to work extra hard to make the code in the second example less clear.

Never too hard.

maintenance programmer's job much more difficult

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.
 
  • #4
Zondrina said:
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.
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.
 
  • #5
Yes. No. No. No. Whenever code is read. Always write for clarity and avoidance of possible errors, except when replying to questions like this.
 
  • #6
Zondrina said:
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.
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.
 
  • #7
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:
  • #8
Zondrina said:
Is there really a disadvantage to writing code like in the second code block?
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.

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?
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.
 
  • Like
Likes STEMucator and FactChecker
  • #9
D H said:
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.
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.
 
  • #10
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
Here's an entry from the International Obfuscated C Code Contest, from the 2012 contest.
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);}
 
  • Like
Likes STEMucator and Merlin3189
  • #13
Mark44 said:
Here's an entry from the International Obfuscated C Code Contest, from the 2012 contest.
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".
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.
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())))
 
  • #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.
 
  • #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:
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.
 
  • #16
newjerseyrunner said:
Usually the only time you care about things like that are supercomputers and kernel code.

There are coding standards even in kernel code.
Linux:
https://www.kernel.org/doc/Documentation/CodingStyle
Don't put multiple assignments on a single line either. Kernel coding style
is super simple. Avoid tricky expressions.
 
Last edited:
  • #18
newjerseyrunner said:
Yes, most projects do.
http://stackoverflow.com/questions/...the-linux-kernel-how-do-they-work-whats-their

A detailed explanation of the difference is here on page 57: http://www.akkadia.org/drepper/cpumemory.pdf
I've found it can make a huge difference in very specific circumstance.

Optimizing branching and memory access is complex (a necessary requirement for good kernel code) , writing it with tricky functions just makes it complicated.
something that is complex can be broken down into simple parts, without being simple itself. This allows mostly smooth functioning with solvable problems.

"complicated" is indicative of something that is problematic, convoluted, difficult and inconsistent.

https://www.englishforums.com/English/ComplexComplicated/dqrvk/post.htm
 
  • #19
newjerseyrunner said:
Yes, most projects do.
http://stackoverflow.com/questions/...the-linux-kernel-how-do-they-work-whats-their

A detailed explanation of the difference is here on page 57: http://www.akkadia.org/drepper/cpumemory.pdf
I've found it can make a huge difference in very specific circumstance.

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

If the condition is frequently false, the execution is not linear. There is a big chunk of unused code in the middle which not only pollutes the L1i due to prefetch-ing, it also can cause problems with branch prediction. If the branch prediction is wrong the conditional expression can be very inefficient.

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.
 
  • #20
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:
  • #21
newjerseyrunner said:
A detailed explanation of the difference is here on page 57: http://www.akkadia.org/drepper/cpumemory.pdf
I've found it can make a huge difference in very specific circumstance.

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

If the condition is frequently false, the execution is not linear. There is a big chunk of unused code in the middle which not only pollutes the L1i due to prefetch-ing, it also can cause problems with branch prediction. If the branch prediction is wrong the conditional expression can be very inefficient.

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.
What you quoted isn't about the ternary operator or branches (if () else ..). Ulrich Drepper is not saying that these things are bad. What he is saying is that how they are used can lead to inefficient use of cache memory. In particular, a block of code like this:
C:
if (<condition>) {
   <do something>
}
else {
   <do something else>
}
If <condition> is usually false, it fouls up the branch prediction and the CPU instruction pipelines aren't valid, and have to be refilled. That's what he's talking about with the execution being non-linear.
 
  • Like
Likes nsaspook
  • #22
nsaspook said:
Optimizing branching and memory access is complex (a necessary requirement for good kernel code) , writing it with tricky functions just makes it complicated.
<begin tongue-in-cheek>
As everyone knows, the standard algorithm for determining whether a year y is a leap year is
C:
bool is_leap (int y) {
if (y%25 == 0)
   return y%16 == 0;
else
   return y%4 == 0;
}
Thanks to the bang (!) and ternary operators, this becomes the one-liner via
C:
bool is_leap (int y) { return !(y%(y%25?4:16)); }
There's still a problem here with regard to highly optimized code. Just as the if version slows down the computer thanks to that decision point, so does the ternary operator. It's just hiding the decision. A decision-free one liner that takes just a few more characters than the terse ternary version is
C:
bool is_leap (int y) { return !(y%(4<<2*!(y%25))); }
<end tongue-in-cheek>The standard implementation of is_leap is of course
C:
bool is_leap (int y) { return (y%4 == 0) && ((y%100 != 0) || (y%400 == 0)); }

Even though that standard implementation doesn't have a single if statement or a single ternary operator, there are at least two, and perhaps as many as five, decision points hiding in that standard algorithm. Kernel and cuda programmers go out of their way to convert those decision-full algorithms to decision-free algorithms.

The standard algorithm is the preferred implementation for everyone but a kernel or cuda programmer.
 
  • Like
Likes STEMucator
  • #24
You probably need to know a little more about how a computer reads a program to fully understand why branch prediction matters so much.

When the CPU is executing a command, logic says that it's grabbing one command, running it, grabbing the next, running it... In reality, that couldn't be further from the truth.

When the CPU is executing a command, it's running it, it's also running the next command... probably the next handful all at the same time. It won't actually complete them until the previous one is done, because it may depend on the results of the previous command. So when it comes to an if, while it's executing the if, it's already also executing what's inside of it. This is called a pipeline. If the if statement fails, all of what the CPU has already done is scrapped and program execution is moved somewhere else. This is wasteful. It also doesn't load one command at a time, it loads large numbers of them in a block. 99.9% of the time, the next command to run, is the one right after it, so it makes sense to load many commands into cache as possible. If the execution of an if fails, the else code, is probably not located in the same block and a completely new block of code has to be loaded into the cache from the RAM.
 
  • #25
Mark44 said:
What you quoted isn't about the ternary operator or branches (if () else ..). Ulrich Drepper is not saying that these things are bad. What he is saying is that how they are used can lead to inefficient use of cache memory. In particular, a block of code like this:
C:
if (<condition>) {
   <do something>
}
else {
   <do something else>
}
If <condition> is usually false, it fouls up the branch prediction and the CPU instruction pipelines aren't valid, and have to be refilled. That's what he's talking about with the execution being non-linear.

I know, this thread has jumped to an entirely different topic concerning branch execution. I was just highlighting an interesting point I saw in the PDF.

I never even knew branch execution was so far-reaching till I read that.

Also, I was just making a comment about the ternary operator itself, and how it doesn't seem to serve too much purpose.
 
  • #26
Zondrina said:
Also, I was just making a comment about the ternary operator itself, and how it doesn't seem to serve too much purpose.

Sometime you just need a quick way to get a value like when printing or setting up const data.

Excessive use is a sign of trouble when you need should use statements to make logic clear and instead use the ternary operator for value expressions because it saves two lines and looks cool when the compiler will reduce it to a jumble of machine optimized code anyway.
 
  • #27
There are usually multiple ways to do anything in CS, usually whatever is most readable is most common.

Also, this was bugging me
Code:
bool is_leap (int y) { return (y > 1752) && (y%4 == 0) && ((y%100 != 0) || (y%400 == 0)); }
 
  • #28
newjerseyrunner said:
There are usually multiple ways to do anything in CS, usually whatever is most readable is most common.

Also, this was bugging me
Code:
bool is_leap (int y) { return (y > 1752) && (y%4 == 0) && ((y%100 != 0) || (y%400 == 0)); }

Is your difficulty with what appears to be a "magic number" 1752?

If so, that's when the Gregorian calendar was adopted in Great Britain and the colonies, to correct significant inaccuracies in Julian calendar that preceded the adoption. In that year (1752), September had only 19 days, not the usual 30.

$$\text{September 1752}$$
$$\begin{bmatrix}\\
Su &Mo &Tu& We& Th& Fr& Sa\\
& & 1 & 2 & 14& 15& 16 \\
17 &18 &19 &20& 21& 22& 23 \\
24 &25 &26 &27 &28 &29 &30 \end{bmatrix}$$
 
  • #29
Zondrina said:
There really is no specific guideline for this. Personally, I like to write my code as compact as I can, but is there really ...
...
What are your opinions?

Its weird, because for me there are two kinds of good. Good Java has plenty of comments, and really long verbose function and variable names that describe what things do, and the code itself will be verbose. Good Python will also have lots of comments, but its less like English and more like Math, short variable names, list comprehensions, lambda functions and the like. The Java is easier to understand, but once you understand the brevity of the Python, and start using it yourself, you become a faster coder as well using the tiny constructs. Once you are familiar with them, they are easy to understand. So in some ways the question is how much of a beginner does your code need to be accessible to?
 
  • #30
Zondrina said:
Also, I was just making a comment about the ternary operator itself, and how it doesn't seem to serve too much purpose.
It's very useful but so is goto in the right context.

Code from a kernel protocol driver I'm writing.
Code:
/* Talk to the ADC via the SPI */
static int32_t daqgert_ai_rinsn(struct comedi_device *dev,
   struct comedi_subdevice *s,
   struct comedi_insn *insn, uint32_t *data)
{
   int32_t ret = -EBUSY;
   int32_t n;
   struct daqgert_private *devpriv = dev->private;

   mutex_lock(&devpriv->cmd_lock);
   if (devpriv->ai_cmd_running)
     goto ai_read_exit;

   mutex_lock(&devpriv->drvdata_lock);
   devpriv->ai_hunk = false;
   devpriv->ai_chan = CR_CHAN(insn->chanspec);
   /* convert n samples */
   for (n = 0; n < insn->n; n++) {
     data[n] = daqgert_ai_get_sample(dev, s);
   }
   mutex_unlock(&devpriv->drvdata_lock);
   ret = 0;
ai_read_exit:
   mutex_unlock(&devpriv->cmd_lock);
   return ret ? ret : insn->n;
}
 
  • #31
The 1752 thing is a UNIX-centric thing. See the man page for the cal command
Code:
cal 1752
.

I've done work with museum accession and cataloging. At many different times Europe and other places were a changing crazy quilt of Julian/Gregorian/Other(French Republican for example) calendars.

1752 is just a drop in the bucket. To see why they did this try looking at the Netherlands in this link:
http://www.tondering.dk/claus/cal/gregorian.php
 
Last edited:
  • #32
nsaspook said:
It's very useful but so is goto in the right context.

It could be useful, like when you decide which object to print:

Code:
  public String getLongDescription(Item playerItem){
      return "You are " + description + "\n" + getExitString() + ".\n" + toString(items)
      + "Player Item: " + (playerItem == null ? "N/A" : playerItem.getName()) + ".\n";
  }

Otherwise, it doesn't seem like its utility spans much further than simplifying things to look cool and eliminating code blocks.
 
  • #33
Zondrina said:
Otherwise, it doesn't seem like its utility spans much further than simplifying things to look cool and eliminating code blocks.

True but eliminating code blocks adds to code readability (my example IMHO) where there is a possible error condition (an early exit with cleanup via goto) OR a 'prior' calculated value to return.
 
  • #34
Literally came across a situation today where I changed a ternary to an if for a very good reason: debugging. Today I wanted to catch a particular case, the less likely case of an ternary and look at the memory. I originally placed the breakpoint at the ternary operator, but hit it way too many times in the case that I didn't want to. So I pulled the operation apart into an if statement and put the breakpoint only in the scope that I needed it. This is the biggest advantage to keeping code well structured.
 
  • #35
nsaspook said:
True but eliminating code blocks adds to code readability (my example IMHO) where there is a possible error condition (an early exit with cleanup via goto) OR a 'prior' calculated value to return.
Outside of C, you should never use goto, you should use scope to clean up:

Bad code
Code:
FILE * fp1 = fopen("/tmp/test.txt", 'w');
if (!fp1) goto error1;
FILE * fp2 = fopen("tmp/test2.txt", 'w');
if (!fp2) goto error2;

error2:
   fclose(fp1);
error1:
    return;

Good code
Code:
struct file_cleanup {
    file_cleanup(FILE * fp) : myfp(fp){}
    ~file_cleanup(){ if (myfp) fclose(myfp); }
    FILE * myfp;
};

file_cleanup fp1(fopen("/tmp/test.txt", 'w'));
if (!fp1.myfp) return;
file_cleanup fp2(fopen("/tmp/test.txt", 'w'));
if (!fp2.myfp) return;   //fp1 is automatically cleaned up
 

Similar threads

Replies
3
Views
3K
Replies
7
Views
2K
Replies
5
Views
4K
Replies
75
Views
5K
Replies
12
Views
3K
Back
Top