This is an excellent point, and one that not enough programmers pay attention to (well, outside of the APL family of languages, anyway!)
This is an excellent point, and one that not enough programmers pay attention to (well, outside of the APL family of languages, anyway!)
}
} // not
} // a single
} // fucking else
// implicit else
// return nullptr
return result;
}
A deeply-indented scope should mean "shit is complicated, think deeply about it," not "there were five times I tried something and elected to punt and return null if it failed." The LLVM style guide has the right idea; if you're gonna punt, early-return.As a side-note, I really wish the C++ community would take a page out of Lisp's book and stop giving closing braces their own lines. But that'll never happen.
Oh for the love of God, please don't! That would make things even more unreadable.
Also, the closing braces are often accompanied by error handling and cleaning up code.
You might like the golang approach better, which is really the Linux kernel approach when I think about it....
int double(int x){
return x * 2;}
instead of like this: int double(int x) {
return x * 2;
}
In Lisp, you would write that like this: (defun double (x)
(* 2 x))
and not this: (defun double (x)
(* 2 x)
)
You can read either with syntax highlighting and the appropriate indentation, but it's much harder to get away with putting the closing brace on the same line in C-like languages because of how few people use something like Smartparens or Paredit and how having multiple kinds of brackets (parens, square brackets, curly braces, and angle brackets) introduces ambiguity.When you said that putting the closing bracket on the same line wouldn't work because of the "lack of Paredit-style editor support" for C-like languages, I thought you meant that the Paredit-style plugins wouldn't work well with/support C-like languages. That struck me as odd, because I use Smartparens when writing Rust, and it works just as well as it does when I write a lisp/scheme. In particular, it handles parens, square brackets, curly braces, and angle brackets just fine (and it even distinguishes between a single quote that's used to start a character literal (which should be paired) and a single quote that indicates a lifetime label (which should not))[0]. I could easily use it to write Rust with closing braces on the same line; the only reason I don't is because it's not the common style in that community.
Based on your last comment, I now understand that you're not saying Paredit-style plugins don't _work_ with C-like languages. You're saying that most programmers who write in those languages don't use those plugins. Is that right? If so, I agree that they aren't widely used and that it'd be hard for anyone to use the formatting style above without adopting a plugin.
[0]: The only thing Smartparens fails to handle is that it does not recognize that a pipe character is a pair when delimiting the arguments for a closure. I'm sure I could fix either Smartparens or rust-mode to fix that issue but so far I haven't been annoyed enough to bother.
[Edited to add a missing close-paren, fittingly enough.]
With Paredit, there are key chords for moving up, down, and sideways (forwards and backwards) on the tree of Sexps, for transposing two sibling Sexps, for grabbing a sibling (before or after) of a Sexp and making it a child ("slurping"), for taking a child of Sexp and making at a sibling ("barfing").
I have not found a reliable way to slurp statements into the scope of an if statement (Paredit kind of works but tends to misplace semicolons and various other things).
The opening curly brace is better like this:
int double(int x)
{ x += 3;
return x * 2; }
I found it's good to have spaces within the braces, including when closing them: int double(int x, int b)
{ if (b)
{ x += 3;
return x * 2; }
else
{ x -= 3;
return x * 4; } }
This naturally jives with a two space indentation, so everything is pleasingly copacetic. I feel I could easiy maintain a 200KLOC code base in this style.Oh, incidentallly, this style is followed in the production rule action bodies of the TXR yacc file parser.y:
http://www.kylheku.com/cgit/txr/tree/parser.y
I wonder how well GCC's newer "misleading indentation warnings" handle this, though.
> C-like languages because of how few people use something like Smartparens or Paredit
However, everyone in C (or C-like) programming with two brain-cells to rub together uses at least auto-indention and brace/bracket/paren matching features in their editor. A stock installation of Vim turns some of it on by default if you open anything with a given suffix like .c or .js.
These editing features work equally well regardless of how you lay out the braces.
More generally, you can specify KEEP and UNDO phasers in a block, that will fire whether the block is left successfully or not. So a typical usage would be `UNDO $dbh.rollback`.
(all I can think of is something where you could handle it with a finally-type clause)
maybe a fn shouldn't have post conditions?
Or are you saying that there are some lines of code at the end checking the post conditions? I'm not exactly sure what that would look like, it sounds a bit insane, especially if you do it for every function. Could you give an example?
Raku has a zero cost way to add arbitrary post processing that kicks in no matter where or how a block of code exits.
This provides a general mechanism accessible by arbitrary user defined control flow related constructs.
Raku also ships with a dozen or so built in constructs such as PRE and POST blocks that are the foundational elements for DbC, plus UNDO and KEEP blocks for transactional semantics, and so on.
Before:
if (a.works()) {
// some code
if (b.works()) {
// more code
}
}
After: if (!a.works()) {
// error handling code, if necessary
return;
}
// some code
if (!b.works()) {
// error handling code, if necessary
return;
}
// more code> if you're gonna punt, early-return
Bail early and you wont have spaghetti code, plus you wont even allocate things to memory you're not even going to use, cause you're going to bail.
I don't know what it is but I once interviewed for an embedded C position. During the interview, I wrote out some code samples. The only issue the interviewer found was that I had "returned early". He said there could basically only be one return in a function and it had to be at the end. I told him I'd never heard of that. He only said it was a "standard" that had to be followed because of the crypo involved in the code base.
Sadly, even though I didn't get the job, that stupid statement of only one return call in a function has stuck with me and lead to many mental arguments.
There are two main advantages:
- it's obvious when the function ends, no hidden early exits in the middle of nowhere
- if you need to do something before returning, there is only one place to do it (e.g. trim the output, e.g. log performances), and it make it easier to move this kind of last mile logic to a different function (if it's of any interest)
About your interview, don't sweat it, is not for that you didn't pass (you could do a great job and yet lose to a more fit candidate)
(Aside from the attraction in small and simple code, each screen in forth is traditionally allocated a designated spot on the hard-drive so it's partially also for space and HDD usage efficiency too)
I haven't seen many developers do this: get a computer screen that can stand in the portrait position.
My setup currently is: laptop monitor + 27" screen in portrait. I never have the trouble of scrolling back up and down again when it comes to reading code.