codethinked (kōdthĭngked) adj. To be consumed by or obsessed with code.

Ten C# Keywords That You Shouldn’t Be Using

Let me start off by saying that language design is hard, very very hard. Not only is the technical implementation of the language incredibly difficult, but creating a language that will satisfy any significant percentage of its users is an almost impossible task. With some languages you have considerations such as backward compatibility that will hold it back, and in others you simply have such disparate types of users that you are forced to incorporate some less-than-pure functionality into the language.

The C# language is an interesting beast born out of a C-style syntax, but with an aim on extreme type safety. Like most every language on the .NET platform, one of its main goals was to keep the developer from doing stupid things, or at least keep the developer from forgetting to do certain things. C# though falls into the category I mentioned above where the users of the language are extremely diverse, used in everything from military hardware to videogames to my blog. Because of that there are certain features that different types of developers are going to expect. Business users, for example, will expect speed of development. They want things to be simple, unbreakable, and just easy to develop in general. Videogame writers will want speed and control. Sure they don’t want things to be super hard to develop with, but ease of development isn’t their top priority.

Because of the fact that I come from the world of business software (and not game development), there are many features in C# that I think the average developer just shouldn’t be using unless they have a very good reason to do so. Some of these are very obvious, and others maybe not so much. All of which could get you in a bit of trouble if you use them incorrectly.

1) sealed – I went ahead and put what is probably the most controversial keyword in this list first. Sealed. There are two types of people in the C# world, those who love sealed and those who want to seal those other people in a tomb (how witty). I am in the latter camp. In terms of the .NET Framework, I can understand why Microsoft would want to make certain things sealed, but in most application it just makes absolutely no sense. If you start hearing people talking about performance improvements of sealed classes, and you’re not working on the space shuttle’s guidance system, then smack them. Smack them hard.

2) goto – Some of you may be looking at this and wondering if it is even in the C# language, and the answer to that is yes, yes it is. Some of you may be aware that a goto isn’t really as evil as Dijkstra’s paper might have led you to believe, it is the abuse of gotos that is really bad. In fact, we have many equivalent statements which do the same thing as a goto, only in a more structured manner which doesn’t allow abuse. These are “return” (when used in the middle of a method), “break”, and “continue”. Have you ever used one of these? Sure you have. Have you used a goto? Probably not, and if you do, you better have a good freakin’ reason. Especially if you are using it for something as silly as exiting from a nested loop.

for (int i = 0; i < 10; i++)
{
    for (int j = 0; j < 100; j++)
    {
        if (someStupidCheck)
            goto dufus;
    }
}

dufus:
    Console.WriteLine("I'm a dufus.");

3) unsafe – Well, if ever there was a keyword that told you not to use it…. Have you ever used unsafe? Probably not. And don’t start. The unsafe keyword is for people who are… well.. unsafe. You don’t want to be whispered about at the water cooler, do you? Basically unsafe means you are going to be using pointers, and we all know what happens when you start using pointers in managed code. And before you go off saying that you thought that all reference types used pointers, go read (and subscribe to) Eric Lippert’s blog. I would have put pointers in this list, but I specifically said “keywords”.

4) ref – You are probably thinking “Whaaaaat? What is wrong with ref? I use it all the time”. And if you are saying that, then well, you need to have your head examined. 9 times out of ten when I see ref being used it is because the developer who used it was too busy writing crappy code to wonder why they needed ref so often. Sure there are times when you need it, but as with almost anything, you better be able to explain to me exactly why you need it. And if you say that your reason is because you need to return five different scalar values from a single method, I am going to call shenanigans and make you write it again. And this time with your brain on.

public static void TooManyResultsYouIdiot(ref int me, ref int no, ref double design, ref byte software)

5) fixed – If you try to use this in your code, then it is likely that you need to be fixed. The fixed keyword is used for pinning. I’m not sure why they called the keyword fixed and the concept pinning, you would think that they would have just stuck with one. How about “pinned”? Too complicated? Right. Anyways, pinning is the process of fixing a value in memory so that the garbage collector won’t move it. You can’t really expect to have a pointer to something if the freakin GC is going to keep shifting it around, can you? But why would the GC keep moving things around? Well, because the GC compacts the heap occasionally. Don’t understand? Well, all you need to know is that it moves crap around and you can’t trust a variable to be in the same place twice. But you don’t have to deal with this unless you are using pointers, which as I already said, you probably shouldn’t be using.

6) stackalloc This is another one of those “unsafe” operations. You know, the ones I said earlier will force you to get checked out by a doctor. Some of you are probably looking at this and wondering what it is, and that is probably a good thing. But if you don’t know what the “stack” is, then that is a bad thing. If that person is you, then you need to do a bit of reading. stackalloc allows you to declare a block of memory on the stack instead of the heap, this allows you to avoid pinning the memory, since it won’t be affected by the garbage collector. Since nothing you are doing relies on this, stay away! If one day you are sitting there and you say to yourself “man I wish I could just allocate this buffer on the stack before I pass it to this method”, then and only then are you allowed to even look up what this keyword does.

7) unchecked – This is a keyword that you really really shouldn’t be using. First because it often doesn’t affect performance all that much, and secondly because it is so misunderstood that it probably doesn’t even do what you think it does. No, it does not turn off any sort of array bounds checking or anything of the like. No, it does not turn off all arithmetic overflow and underflow checking. It only works with integers. Yep, good old Int32. And you know what else, all integer math in C# is unchecked by default. Unless you turn it on via an option in the project, command line option, or using the “checked” keyword. So, the next time that someone wants to use “unchecked” because they need to speed up a loop, bet them a significant amount of money (or lunch) that it won’t do any good. Cause you’ll win.

8) struct – This is another one of those keywords that people are going to gasp and throw their hands into the air exclaiming that I have no idea what I am talking about. Well, I hate to break it to you, but you probably don’t know what you’re talking about. Many people use structs without understanding the very deep implications of using them. Just to name a few… they use ValueType.Equals instead of Object.Equals, if you pass a struct to a method then the struct is copied, but remember that reference types aren’t on the stack, so just their reference is copied. This can produce some odd behavior. Also, it is possible to box a struct and then have a modified version get passed around when you weren’t expecting it. The copy semantics of structs alone should make you pause if you are considering using one. There are a large number of pitfalls when dealing with structs, so unless you know why you are using it, don’t. Besides, heap allocations are so cheap now, right?

9) volatile – This is yet another keyword that falls squarely into the learn before you use it category. I say this because this is not a keyword to be avoided, but simply a keyword that should be used properly. If you have a field which is a reference type (or a few other specific types) and you know that you are going to be accessing it regularly from multiple threads, then you can mark it as volatile. Volatile basically tells the compiler and jitter to not allow certain optimizations which could cause trouble in multi-threaded code. As with anything though, it is never as simple as it looks.

10) implicit – This keyword made the list because it, in my opinion, can cause very subtle bugs. Not to mention the fact that there are very few legitimate uses for this in most software. The implicit keyword comes into play when implementing conversion operators and it signifies an implicit cast between two types. Now you may not be familiar with the terms “implicit” and “explicit” cast, well, implicit means that the cast just happens (like from short to int) and explicit means that you have to tell the compiler to do it (like when going from int to short). You can do some interesting things, like this:

class Program
{
    static void Main(string[] args)
    {
        Class1 variable = new Class2();
    }
}

internal class Class1
{
    public static implicit operator Class2(Class1 d)
    {
        return new Class2();
    }
}

internal class Class2
{
    public static implicit operator Class1(Class2 d)
    {
        return new Class1();
    }
}

Notice how we are assigning an instance of “Class2” into a variable of type “Class1”. And it compiles and works because an implicit cast is going on here. Sure there are very good uses for this, but there about 18 million more abuses for this. Most likely, if one type can be assigned to a variable of the other type, then it should inherit from it. This is not the case in reference types though, which for the most part, is why this behavior exists.

I’m sure that many of you will disagree with my list, and that is good. Please make sure you leave me a comment and let me know why you think the list is wrong, and what I should add or remove in it!

Comments

zproxy

Every tool has its job...

zproxy

April 2. 2009 04:23

Estonia
Ivan Porto Carrero

I'd like to see the out keyword in your list too. if you're going to return more than one result from a method. You might try to use an array (untyped) or a DTO instead. Much cleaner IMHO

Ivan Porto Carrero

April 2. 2009 05:32

Belgium
Justin Etheredge

@Ivan Agreed, the out keyword and the ref keyword got a bit hand-in-hand.

Justin Etheredge

April 2. 2009 08:30

United States
Scott Watermasysk

If you ship software, Sealed can be an important keyword. While as a dev it is nice to say you are on your own if you screw it up, support costs alone usually justify its' existence.

For internal LOB or one off applications, I agree with you.

Scott Watermasysk

April 2. 2009 08:31

United States
Justin Etheredge

@Scott Agreed, there are certain situations where it is needed due to a class not wanting to be supported, needing to be changed in the future, etc... But for 90% of applications out there, people use it for silly reasons and just cause headaches for everyone else. And then there is also some software that uses it for a good reason, but then goes a little crazy with it.

I for one would rather see an internal class than a sealed class, at least then you aren't taunting me. Smile

Justin Etheredge

April 2. 2009 08:34

United States
Khalid Abuhakmeh

I think Ivan Porto Carrero is kinda right about the out keyword. I try to avoid it like the plague but even the plague strikes sometimes.

Khalid Abuhakmeh

April 2. 2009 08:36

United States
barryd

Sealed is a good one when you start writing objects that are used to generate security contexts, authentication tokens, authorisation bits, etc. Those are all prime cases for sealed classes, even in internal/LOB libraries and applications.

Oh and of course attributes. Attributes should be sealed obviously.

barryd

April 2. 2009 08:43

United Kingdom
vijay

i think all these keywords have their place.
wouldn't it be easier to guide their usage rather than suggesting they shouldn't be used at all?

fortunately, these keywords aren't in java, so n00bs tend to avoid them anyway.

vijay

April 2. 2009 09:06

Australia
D. P. Bullington

Any construct, in the hands of the unenlightened, can be used poorly. The only keyword in the list above that would raise red flags and cause me to pull the fire alarm is GOTO. All other keywords can and should be used WHEN needed and with some understanding. I mean seriously, I have seen LINQ used poorly; I have seen OOP used poorly. Its all a matter of context and expertise.

D. P. Bullington

April 2. 2009 09:10

United States
Ryan Shriver

Funny how C# got much of it's design ideas and language syntax from Java, and the 10 keywords you provide here don't exist in Java (with the possible exception of fixed - if I understand your definition).

Coincidence? Smile

The fact that there's a keyword called "unsafe" is just too funny.

-ryan




Ryan Shriver

April 2. 2009 09:10

United States
Justin Etheredge

@vijay I never said that they shouldn't be used at all (well, maybe the title said that a little Smile ), but in the post I outline that many of these keywords are easily misused, and therefore should be carefully considered. "10 Keywords in C# that you should carefully consider before using in your particular application" might not have made such a great title.

@D.P. Agreed, if you know why and how to use them, then they should be used in moderation. The problem is that lots of smart people know how to use things, but still use them for pointless reasons.

@ryan Yeah, I still chuckle when I see "unsafe" Smile

Justin Etheredge

April 2. 2009 09:17

United States
Antao

I would say this a list o keywords that should be used carefully, not that you shouldn't use them.
On my OpenCV wrapper I use 'unsafe' and 'fixed' all over the place. That's what they are intended for.
If you are coding an web site. I would say, don't use them. Ever...

Antao

April 2. 2009 09:18

Portugal
Matt Casto

I've been bitten by using a struct instead of a class and not realizing the consequences in the past.

As others have said, most of these aren't "don't use them" but "don't use them unless you understand them".

Matt Casto

April 2. 2009 09:33

United States
Krishna

Apart from "ref", I cannot see any inexperienced programmers using these keywords. It is very likely that someone who is using these keywords in a wrong way was probably experimenting in good faith.

Almost all of these keywords are useful in one context or the other. Even goto's can be useful too for increasing performance (http://kerneltrap.org/node/553/2131)


Krishna

April 2. 2009 10:02

Josh

Obviously you've never had to write any .Net software that mainpulates huge amounts of in memory bitmap data. Then you'd very quickly find yourself thankful for that unsafe keyword.

Josh

April 2. 2009 10:04

Germany
Jonathan Pryor

@Ivan you have to be kidding -- returning an untyped array is better than using 'out'?

Requiring casts is preferrable to keeping strongly typed data?

I can understand not liking 'out', but if you must avoid it then use a typed value like a Tuple, KeyValuePair, or some other strongly-typed value.  Preferring untyped data is just...bizarre.

(Also, it should be noted that using 'out' can be faster than returning a custom data type, struct or reference, so this may be an API design consideration.  It can also promote more consistency with the existing framework, e.g. int.TryParse.)

Jonathan Pryor

April 2. 2009 10:08

Justin Lee

Well, as what Antao and Josh says, some of these keywords are useful in certain scenarios, especially during interop and manipulating memory data. Agreeably, a normal developer should not need to use any of these keywords at all, unless he/she knows what they're doing. I tend to avoid most of these keywords anyway.

Justin Lee

April 2. 2009 10:24

Canada
Paco

Another keyword to avoid is "new" in the case of overriding a non-virtual implementation

Paco

April 2. 2009 10:44

United States
Niki

It really depends on what you're doing. If you're writing an ASP.NET website you probably won't need any of these keywords.

But now imagine your code revolved around manipulating arrays containing millions of complex numbers. Imagine each of these complex numbers is stored as a separate object on the heap. Imagine each of them has to be allocated separately. Imagine the GC, keeping track of all of those millions of complex numbers you create each second. Imagine changing one of those complex numbers in one array and erroneously changing five other arrays at the same time.

Now that's why I wouldn't want to do something like that in Java. structs are great, as long as you know what they do and don't confuse them with C++ structs.

Niki

April 2. 2009 10:52

Germany
Justin Etheredge

@Niki I would argue that most people doing these sorts of applications aren't using C# very often anyways. But maybe I don't have my ear to the ground in the "millions of complex numbers" application genre.

Justin Etheredge

April 2. 2009 10:54

United States
Brian Lowry

Good list. I disagree with the out keyword in the comments. I think it can serve a very useful purpose when developing APIs and if you don't want to force your users to consume an out variable, then provide an overload that doesn't use it.

bool Validate(target, out RuleViolationCollection violations);
RuleViolationCollection Validate(target);

Just my opinion though...

Brian Lowry

April 2. 2009 11:31

United States
Ryan Gray

@Paco - That is a solid number 11!

Ryan Gray

April 2. 2009 11:38

United States
Paco

@Ryan Gray: yes the L from solid.

Hmm I just checked this in mono (and I guess MS.Net will do the same):
int i = int.MaxValue + int.MaxValue;

I got the following warning:
The operation overflows at compile time in checked mode(CS0220) msdn.microsoft.com/.../y169h3te(VS.71).aspx

The compiler settings in ms.net and mono are different. So I disagree with unchecked not needed, because your code will compile different on a different compiler.

Paco

April 2. 2009 13:00

United States
Niki

@Justin: Well, the number-crunching/signal processing applications I've seen in the last 10 years often had the same problems that other applications have: Applications become bigger and bigger, which makes development harder. User want simpler user interfaces. Interfaces to different systems become a requirement. That's the kinds of problems where Java and C# really shine in contrast to typical "number-crunching languages" like Fortran or C++.

By the way: you're probably aware that all the "oddities" you list for structs apply to ints or bools, too. Would you recommend we shouldn't use those value types, and instead use reference-type wrappers? Then why should things like System.Drawing.Color or System.Drawing.Point be reference types? I find it much more natural that they behave like int's or double's.

Niki

April 2. 2009 13:29

Germany
Justin Etheredge

@Niki Point taken, I honestly am not in those fields, so I am not aware of their "tools of choice".

And yes, the "oddities" of reference semantics for some reason don't seem to odd to developers when they are dealing with primitives such as integers and booleans. But when you declare something that looks like a class, but then operates under totally different semantics, it can surprise some people. Again, I'm not advocating that we don't use these features at all, I'm advocating that people educate themselves.

Justin Etheredge

April 2. 2009 13:37

United States
Jonathan Pryor

@Justin How do you define "something that looks like a class, but then operates under totally different semantics"?  Does "containing methods" fit that description?

If so, then int doesn't fulfill the definition, as it has several methods -- CompareTo(), Equals(), ToString(), etc.

Or are you operating under the Java "exclusion" principal -- "all types except those in [insert list here] are reference types."

Jonathan Pryor

April 2. 2009 14:02

United States
Justin Etheredge

@Jonathan I'm referring to the definition of the struct themselves, I wasn't very clear on that. Developers create them in a very similar manner, and then you can even use them in a very similar manner (why does the C# compiler let you use the "new" operator with them?)

And I would say that even structs which have more than one value can be confusing as well. As an example, the Point struct that was mentioned earlier. I'm not saying that it isn't a struct for very valid reasons, but I am saying that it can be confusing to developers. And most developers don't understand the implications of substituting one for the other. They just hear that they are "faster".

Justin Etheredge

April 2. 2009 14:07

United States
Jonathan Pryor

Why does the C# compiler let you use "new" with them?  How else would you call the non-default constructor?  A new struct-specific keyword?

Other reasons for the simularity is that it makes the C# grammar simpler, making compiler design maintenance easier.

As for developers hearing that something is faster and using it because of that...that should be a shootable offense.  Profile first! (Unless you're dealing with a specific problem domain, understand all the limitations, and require the features involved.)

Jonathan Pryor

April 2. 2009 14:40

United States
Charles Feduke

>> So I disagree with unchecked not needed, because your code will compile different on a different compiler. <<

That.  

I got burnt answering a SO question where I converted example C code into C# and the questioner had "Check for arithmetic overflow/underflow" checked for whatever reason.  If your code block requires unchecked surround it as such.  Its all part of self-commenting code anyway.

Charles Feduke

April 2. 2009 14:46

United States
James

I'm not a fan of goto either, but it is necessary since switch/case statements require a break.  Goto is the only way to get fall through.  Just goes to show that every keyword is there for a reason, even if it has the chance of abuse.

James

April 2. 2009 14:51

United States
Daniel

@James: switch should probably be on the list too =)

@Justin: I gotta disagree with sealed.  FxCop and framework design guidelines recommend sealing things you don't intentionally mean to allow others to inherit.  Ideally, you should plan out and know which of your classes you want public and inheritable, and therefore when to and not to use sealed.  Sealing everything or leaving everything 'all hanging out' are both bad design, IMO.

Many of the others you can't avoid when it comes time to do any sort of COM interop.  I recently had to write a managed wrapper around some C stuff, and had to use about all of these.

Daniel

April 2. 2009 16:16

United States
Andrey Titov

I suggest to add switch to this list. Most of switch usings indicates poor OOP design. Almost every switch can be eliminated by using polymorphism, strategy pattern or lookup dictionary. Often switch violates DRY principle, often it introduces magic numbers. So if you goes to write switch, stop and think how it can be expressed without switch. I'm sure the alternative solution would be more elegant and more maintainable.

Andrey Titov

April 2. 2009 16:20

Russia
Tony

You can use the state design pattern to get rid of switch statements as well. I'm a huge fan but it can be overkill for simple logic flow.

I think it's ok to use structs as long as you are sure to pass them with the ref keyword whenever you use them. Smile Kidding...


Tony

April 2. 2009 17:07

Justin Etheredge

@Tony I only use structs in my programs and then just use ref everywhere!

Justin Etheredge

April 2. 2009 17:13

United States
Roger

Nice article, I can agree with a lot of it.  I just think you missed the most important one of all.  The most often abused...

-------------> if <-------------

I know it sounds silly, but have really looked hard at method with several if statements?  Often they can be removed or refactored out.  Take a closer look next time you see more than one or two if statements in a function.  Bottom line is simplify.

My complete rant on the subject is at:
http://csharptest.net/?p=198

Roger

April 2. 2009 23:39

United States
Niki

@Andrey: I agree that switch is often used by people without OO skills to simulate polymorphism, which is bad. But forbidding the switch statement wouldn't do any good, they'd just use if/else instead, making the code even messier. You'll can't teach good OO design be forbidding keywords.

And switches are really useful sometimes: for example pretty much any language parser has in its heart a
switch (GetNextToken()) { case Token1: ... }
statement. Of course you could write an alternative "OO-style" solution, where tokens are classes, and instead of switches you have virtual methods, but that would violate DRY big time, and lead to a maintainance nightmare.

Niki

April 3. 2009 02:23

Germany
BenL

I feel that this might have been better as a series of posts. There certainly are good and bad use cases for each of these keywords and the concepts they represent (with the probable exception of goto). That any of them should not be used, however, is obvious only to someone who already understands them on a fairly deep level, someone who is probably already qualified to use them anyway.

   Moreover, writing a few sentences about the effects of each keyword and asserting that they are clearly almost never necessary is not helpful, even if you are right. In particular, it does not encourage actually learning the correct usage of any of these things. Encouraging people not to do things they might screw up is not quite as good as showing them how to do better. For example, it's all very well to say unsafe code is scary and confusing and won't give you the performance benefit you might think it would, right up until you need to use unsafe code to interface with native-code libraries in some capacity. Now you either need to learn how to write unsafe code, or use some other language. "Well, you shouldn't be doing that" isn't always an excuse.

   You undoubtedly have opinions on how these keywords should be used, but "language design is hard, very very hard," and there is more than one side to each of these arguments. Show us you understand in more detail.

BenL

April 3. 2009 10:47

United States
David Arno

Interesting that you use existing from nested loops as a bad use of goto. In my book, it is the only acceptable use of goto. C# lacks break to labels and break to labels are a good thing, so one must use gotos instead.

David Arno

April 3. 2009 11:33

United Kingdom
Justin Etheredge

@David My point is that if you are using gotos to jump out of nested loops, then there is a chance that you might need to refactor the code. There is probably a better way to write it. But I agree, that in certain situations (as was nicely described in Code Complete) using gotos to jump out of nested loops can look nicer than the alternative.

Justin Etheredge

April 3. 2009 11:44

United States
Al Tenhundfeld

Interesting list.

I'm sure it will surprise readers here, but many times in my career, I've heard a developer say something like this: reference type arguments are passed by ref by default; thus the ref keyword is only meaningful with structs, i.e., value types. Frightening, I know.

So, while I sometimes use ref and struct, I understand your point about avoiding their use unless you really truly understand the implications. And in my experience most people do not understand them, or at least do not think them through well enough.

I have mixed feelings about sealed. I tend to leave classes open, but I also respect the argument that if you publicly expose an inheritable type, you're implying that inheritance has been considered and members are marked protected and virtual appropriately.

I'm curious what people think of Jeffrey Richter's proposal to add a keyword that is between sealed and open; closed is the term he uses I think. The point of the keyword is tell developers that they *can* inherit from the class, but the class was not designed with inheritance in mind.

Al Tenhundfeld

April 3. 2009 13:51

United States
trackback

Trackback from gOODiDEA.NET

Interesting Finds: 2009 04.01~04.05

gOODiDEA.NET

April 4. 2009 19:05

trackback

Trackback from gOODiDEA

Interesting Finds: 2009 04.01~04.05

gOODiDEA

April 4. 2009 19:06

trackback

Trackback from #.think.in

#.think.in infoDose #24 (30th Mar - 3rd Apr)

#.think.in

April 6. 2009 16:12

Brian

Interesting list, but I'm afraid I violate most of it.  Between interfacing with unmanaged code and maintaining a stable API for external use, many of these keywords are invaluable.  They also tend to generate extra review chatter, so it works out in the end.  There is nothing like an unfamiliar keyword to focus attention on a block of code.

Brian

April 8. 2009 16:47

United States
jason kikel

The product I work on has millions of lines of C++ that aren't going away any time soon.  When incorporating new managed components (accessible via COM or C++/CLI bridges) we must use the fixed keyword.  No getting around it.

jason kikel

April 9. 2009 07:32

United States
Sulumits Retsambew

thanks this is good to know especially for the newbie like me ..lolz

Sulumits Retsambew

May 31. 2009 13:50

France
trackback

Trackback from Rob Conery

You’re Not Your Data Access

Rob Conery

June 11. 2009 20:52

trackback

2009... Oh How I Will Miss Thee. Kinda.

2009... Oh How I Will Miss Thee. Kinda.

CodeThinked

December 30. 2009 17:11

Add Comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading