# Code Readability for "Higher" Level Languages

nsaspook
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.

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)); }

Mark44
Mentor
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 calender 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}$$

There really is no specific guideline for this. Personally, I like to write my code as compact as I can, but is there really ...
...
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?

nsaspook
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)

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;
mutex_unlock(&devpriv->cmd_lock);
return ret ? ret : insn->n;
}

jim mcnamara
Mentor
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:
Homework Helper
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.

nsaspook
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.

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.

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:

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

nsaspook
Outside of C, you should never use goto, you should use scope to clean up:

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
Baloney. I agree your goto example is bad 'need to use goto' code, mine is not in the correct context (C device driver).
http://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c

http://c.learncodethehardway.org/book/

Last edited:
D H
Staff Emeritus
Outside of C, you should never use goto, you should use scope to clean up:

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;
That's bad code because you left the file pointer fp2 open. That would be considered "good code" in some circles that code in C had you added a fclose(fp2) just before error2.

It would of course be considered very bad code in the C++ world. It would be non-compilable code in Java (even without the pointers).

Good code <elided>
I wouldn't quite call that "good" (raw pointers, leaky abstraction), but I do get the point, and it is a very important point. Well-written C++ code doesn't need gotos because the objects clean up after themselves on destruction. This goes by the terrible acronym "RAII" (Resource Allocation Is Initialization). This doesn't just apply to memory. It applies to resources of all types. I'm biased, but C++ is better in this regard than garbage collection languages. C++ doesn't have a "finally" keyword because it's not needed. Instances of classes that follow RAII magically clean themselves up when they go out of scope.

nsaspook
Just used another ternary operator to add a delay enhancement to my local Linux branch for SPI transfers. If you don't change the field from the default of 0 the old 10us remains but if you set cs_change_usecs to a value >0 it's used instead of the fixed delay. Quick and easy to understand.
Code:
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 57a1950..3f784df 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -836,7 +836,7 @@ static int spi_transfer_one_message(struct spi_master *master,
keep_cs = true;
} else {
spi_set_cs(msg->spi, false);
-                               udelay(10);
+                               udelay(xfer->cs_change_usecs ? xfer->cs_change_usecs : 10);
spi_set_cs(msg->spi, true);
}
}
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 856d34d..131f145 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -622,6 +622,7 @@ struct spi_transfer {
#define        SPI_NBITS_DUAL          0x02 /* 2bits transfer */
#define        SPI_NBITS_QUAD          0x04 /* 4bits transfer */
u8              bits_per_word;
+       u8              cs_change_usecs;
u16             delay_usecs;
u32             speed_hz;

Boing3000
Gold Member
are there actual advantages to writing code so compactly?
There are only disavantages. A few of them have already been point out. This question is about High level language. You compact nothing by avoiding to write two return one "if" and two braces. The expression tree would be the same, if you had not introduced a bug. The correct equivalent is
Code:
return !booked ? booked = true : false;
So, concretely, you have shoot yourself in the foot already by asking explicitly to read 'booked' twice (**). It was too hard.

There is is more. Writing high level language means your code will have a long lifetime and be maintained by coworker.
This original code is surely a made up example. There is no way a real booking will use such a method.
Here is what's going to happens. The method will be called in a dozen places, expecting a bool.
One years later, another smart ass will turn (private) booked into an enum (confirmed state added), or worse, a object with bool conversion semantic (called trice ***)
So the method will need anyway to have its braces back.

Code readability, for any type of language, should express your intent with less possible obfuscation. In most case, the code will be its own documentation, and won't need even a glance at the comments. And in most cases, it will be more efficient.