Code Readability for "Higher" Level Languages

  • Thread starter STEMucator
  • Start date
  • #26
nsaspook
Science Advisor
949
1,398
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
1,518
618
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
34,165
5,782
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}$$
 
  • #29
196
42
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
nsaspook
Science Advisor
949
1,398
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
jim mcnamara
Mentor
4,065
2,525
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
STEMucator
Homework Helper
2,075
140
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
nsaspook
Science Advisor
949
1,398
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
1,518
618
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
1,518
618
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
 
  • #36
nsaspook
Science Advisor
949
1,398
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
Baloney. I agree your goto example is bad 'need to use goto' code, mine is not in the correct context (C device driver).
http://koblents.com/Ches/Links/Month-Mar-2013/20-Using-Goto-in-Linux-Kernel-Code/
http://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c

http://c.learncodethehardway.org/book/
 
Last edited:
  • #37
D H
Staff Emeritus
Science Advisor
Insights Author
15,393
685
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;
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.
 
  • #38
nsaspook
Science Advisor
949
1,398
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;
 
  • #39
Boing3000
Gold Member
332
37
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.
 

Related Threads on Code Readability for "Higher" Level Languages

  • Last Post
Replies
13
Views
5K
Replies
19
Views
986
Replies
5
Views
2K
Replies
1
Views
2K
Replies
7
Views
7K
Replies
80
Views
10K
  • Last Post
Replies
1
Views
12K
  • Last Post
Replies
5
Views
1K
  • Last Post
Replies
3
Views
2K
Top