I’ve programmed in both C# and VB.NET for years, but primarily in VB. I’m making a career shift toward C# and, overall, I like C# better.
One issue I’m having, though, is curly brace soup. In VB, each structure keyword has a matching close keyword, for example:
Namespace ...
Class ...
Function ...
For ...
Using ...
If ...
...
End If
If ...
...
End If
End Using
Next
End Function
End Class
End Namespace
The same code written in C# ends up very hard to read:
namespace ... {
class ... {
function ... {
for ... {
using ... {
if ... {
...
}
if ... {
...
}
}
}
// wait... what level is this?
}
}
}
Being so used to VB, I’m wondering if there’s a technique employed by c-style programmers to improve readability and to ensure that your code ends up in the correct “block”. The above example is relatively easy to read, but sometimes at the end of a piece of code I’ll have 8 or more levels of curly braces, requiring me to scroll up several pages to figure out which brace ends the block I’m interested in.
11
Put your starting curly brace in the same “rank” as your ending one, like this:
namespace ...
{
class ...
{
function ...
{
for ...
{
using ...
{
if ...
{
...
}
if ...
{
...
}
}
}
// It's the `function` level!
}
}
}
13
- Depending on your IDE: put your cursor at the open/close brace and it’ll highlight both that and the corresponding brace.
- Collapse the block and it shows you where it opens/closes.
- Write smaller code blocks. Seriously. Check out
Clean Code
, and never run into this problem again (and have more readable/maintainable code).
One note, the following is valid c# syntax that might help your particular situation:
using (var type = new MyDisposable1())
using (var type2 = new MyDisposable2())
{
/* do what you will with type2 and type2 */
}
5
In general, when it gets hard to match braces in whatever style – it probably means the method is too long and should be re-factored.
I think you need to tough it out with the braces. Eventually they will become second nature to you and you will be wondering how you ever lived without them.
Make sure they are indented appropriately though, and that some spacing convention is being followed (doesn’t matter which).
1
A common convention is to add a comment after the closing brace to indicate the structure that it’s closing:
if {
...
} // end if
while (condition) {
...
} // end while
etc. I’ve never warmed to this convention myself, but some people find it helpful.
11
I remove 2 levels of nesting by collapsing the namespace and class scopes horizontally. Notice the methods are flush with the left edge of the screen. I don’t see the point in losing 2 levels of indentation in every file.
After that it’s rare you’ll ever have nesting more than 4 levels deep.
namespace FooNameSpace {
class Foo {
public void bar()
{
while(true)
{
while(true)
{
break;
}
}
}
public void fooBar()
{
foreach(var item in FooList)
{
foreach(var b in item.Bars)
{
if(b.IsReady)
{
bar();
}
bar();
}
bar();
}
}
}}//end class, namespace
3
I recently decided to try and formalize two rules about flow control constructs that basically go like this:
- You should have nothing but necessary code-flow constructs
- You should make the code-flow constructs as small as possible
For exactly the reasons you have mentioned and are clearly aware of, I think these are great rules to follow. There are a couple simple techniques you can employ to accomplish them:
- Exit scope as soon as you can (this includes the scope of loops as well as functions)
- Watch for elses that could be mitigated by exiting the function from the preceding if and apply the scope exiting technique as I mentioned
- Reverse your conditional checks when the code inside an if is great than that outside
- Factor code inside of a loop out to another method when the size of the loop grows to obscure the rest of the method
- Watch for any scopes that only contain another scope, for instance a function whose entire scope is filled by an if with nothing outside of the if
I detailed here examples of how not following these can end up with you doing as you said and putting code in the wrong code block, which is bad and an easy cause of bugs cropping up during maintenance.
6
This is one of the oldest causes of warfare in computing, unfortunately. Reasonable arguments can be made from both sides (better vertical real-estate economy versus easier ability to visually match opening brace with closing brace), but in reality a simple source-code formatter will resolve everything for you. MS Visual C# has one built in that works well.
Be warned however that if you are working as part of a team you will be expected to conform to the conventions used by that team, so it pays to gain some familiarity with both styles and to refrain from getting religious over brace styles.
So while you’re learning by all means focus on the style that makes it easier for you to learn, but keep half an eye on the other while you’re at it and you’ll do fine.
1
Use Resharper, which will help recommend ways to reduce nesting. Also, read Bob Martin’s book Clean Code, which emphasizes that a function should only do one thing, and therefore each function should only be a half-dozen lines long, so you won’t have that many levels of nesting to worry about.
There is an add-on to the editor that may help you at: C# Outline.
The add-on extends the VS20xx editor for C# by adding features to collapse, expand and highlight nested blocks of code. These features allows for easier editing and reading of nested contents of code blocks such as if, while, etc.
0
If you write your Code in Visual Studio, there’s also a Plugin that shows you vertical dots between the beginning and the end of every structure that you construct.
But overall I think it’ll just take some time until you’re used to the “Curly-Braces-Soup”. (Btw, I really like that expression. Sounds a bit like a Episode-Name for The Big Bang Theory)
Indentation tells you where you are, in both styles of syntax. If you write either a VB program or a C# program on a single line, you will soon not be able to tell where in the nested syntax you are. The machine parses the block ending phrases or curly braces, but humans need indentation.
Block ending phrases come from an era of punched cards and paper tape, when programming was much less interactive and visual. Or, really, not interactive at all. It was difficult to enter programs, and so programmers needed compilers to be very clever about syntax analysis and error recovery.
In that bygone era, the edit-compile-run cycle might have involved preparing punched cards with a card puncher, and then lining up to a job submission window where a clerk took the punched cards and submitted them to the machine. Later, the programmer would collect the output (printed on paper) from another window. If the program had errors, the output would consist of just the compiler diagnostics. When the turnaround times are long, the added cost of typing end if
instead of just )
is justified if it helps to improve the quality of diagnostics, because the programmer needs to correct as many errors as possible in a single iteration to reduce the number of time-wasting iterations through the job submission window.
When a closing curly brace is missing, it is hard to tell which open brace is the one which is not closed. (The compiler may have to parse indentation to make an educated guess.) If you delete a closing brace inside a function, then it looks like the entire rest of the file is part of that function, resulting in a flurry of unhelpful error messages. Whereas if you have an end function
syntax, the compiler can deduce where the erroneous function ends, recover, and parse the subsequent functions properly, giving you additional diagnostics, if any, which are meaningful.
When you’re working in code-aware text editor which automatically indents and colorizes your code, on a high resolution screen where you can see sixty or more lines, the arguments for those kinds of clumsy languages no longer apply. You can incrementally edit and rebuild programs so fast that you can just deal with one error at a time. Moreover, by seeing large sections of the program simultaneously on the screen and maintaining proper indentation, you can reduce the occurrence of those kinds of nesting errors in the first place. And good programming text editor will even flag some kinds of syntax errors as you type. What is more, there are folding editors which will collapse the blocks of a program based on its syntax, giving an “outline-like” view of its structure.
Lisp used parentheses from the beginning and perhaps, not coincidentally, Lisp hackers pioneered programming as an interactive experience by building systems which accepted programs in small chunks (expressions).
In fact, you don’t need ending symbols at all, as the Python language illustrates. The identation can just be the structure. Humans already use indentation to grok the structure of code even in languages where the machine relies on ending symbols or phrases.
If you are using an IDE, Just press Crtl + k + D and the IDE will do the rest of the work.
2