This post was migrated from Justin’s personal blog, 'Codethinked.com.' Views, opinions, and colorful expressions should be taken in context, and do not necessarily represent those of Simple Thread (and were written under the influence of dangerous levels of caffeination).

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!

74 Comments

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

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

Reply
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. 🙂

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

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

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

Reply
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? 🙂

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

-ryan

Reply
Justin Etheredge

@vijay I never said that they shouldn’t be used at all (well, maybe the title said that a little 🙂 ), 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" 🙂

Reply
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…

Reply
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".

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

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

Reply
Jonathan Pryor

@Ivan you have to be kidding — returning an untyped array is better than using ‘out’?

[i]Requiring[/i] 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 [i]may[/i] be an API design consideration. It can also promote more consistency with the existing framework, e.g. [i]int.TryParse[/i].)

Reply
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 [b]normal[/b] 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.

Reply
Paco

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

Reply
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 [i]that’s[/i] 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.

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

Reply
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…

Reply
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) http://msdn.microsoft.com/en-us/library/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.

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

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

Reply
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 [i]int[/i] 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."

Reply
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".

Reply
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. [i]Profile first![/i] (Unless you’re dealing with a specific problem domain, understand all the limitations, and require the features involved.)

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

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

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

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

Reply
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. 🙂 Kidding…

Reply
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…

————-> [b]if[/b] <————-

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

Reply
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 [i]big time[/i], and lead to a maintainance nightmare.

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

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

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

Reply
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 [i]ref[/i] and [i]struct[/i], 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 [i]sealed[/i]. 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; [i]closed[/i] 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.

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

Reply
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 [b]must[/b] use the fixed keyword. No getting around it.

Reply
Jim Brissom

I’m not going to talk about how I think this post to be worthless, just highlighting _one_ aspect of those keywords, and additionally mixing in personal attitude, but just let me comment on the sealed keyword:

Actually, there was a discussion among the designers of C# if every class should be sealed by default, and that would’ve been a very, very good idea – it’s just this concept alienates what most people indoctrinated by half-hearted teachings of OOP.

But, just for a minute, indulge me please, and honestly think about how many of the classes you encounter in your daily work are actually MEANT to be inherited. Designed from the ground up to be used as a base class. Because that’s what a class designer has to do, otherwise, inheritance is completely meaningless and leads only to code rot. 99.9% of all classes that are around are NOT designed to be inherted, and inherting from them does more harm than it is useful.

This is highly suspect to people who were told during their education that inheritance is one of the most fundamental building stones of OOP, and well, it is. But it has to be applied correctly.

Designing a class so that it makes a good base class is hard. Really hard, for all but the trivial cases. And judging how hard it already is for most people to provide a good interface design for their classes, you cannot really expect them to anticipate further uses of their classes when it comes to inheritance. This is why the majority of classes are so poorly appropriate as a base class. Which is why sealing any class by default is a good thing.

Reply
Justin Etheredge

@Jim Yep, I’ve heard all of your arguments before. Unfortunately I don’t agree with you. I don’t want you to bind my hands solely because you think I shouldn’t be able to change your class. Especially if you’re not going to give me the source.

And yes, I agree that to design a class for proper inheritance is hard. But I don’t think that should trump giving me the ability to make a choice.

What you are advocating for is stripping me of all choice and flexibility unless the creator of the class *chooses* to give me that control. Ick, sounds very ivory towerish to me.

And as a final point, if you go look at almost any dynamic language they give you virtually complete control to change anything. And yet the sky does not fall. Because people quickly learn that while you can do anything, doesn’t mean you should, but having the choice makes your life a lot easier.

Reply
Holger Kreissl

Good list… But like people already have written its not that black and white. Its true… You SHOULD not use OUT if not necessary. Returning more that one result is not in the meaning of SRP. Or probably seperation of concerns is missed. If more than one result is used by context, its a more clean style to use an own return object with the needed properties or a typed enumerable as return value.

Reply
Trump

I have to agree with you, but I was looking for reasons not too as I read your article. I’ve been programming for a long time. Started with Pascal, then VB, the VC, then PHP, Java, and now C#

I used many of those like STRUCT but that was before I was using OOP and Classes. I guess VB lingers in the soul somewhere. 🙂

Reply
Hugh

Hi

I think your blanket rejection of many of these features is unjustified Justin.

A struct allows you to embed a member directly into the storage layout of a datum, for example declaring a class with only value type members means that all of the objects data is packed into a contiguous memory block.

This makes marshaling that object’s data much easier (in terms of processing) than if each member had been a reference type (in which case each member would be (in reality) a pointer to the data – i.e. an object graph).

By preventing people from creating their own structs you make it much harder to do this – granted the run-time layout is an implementation issue but that does not mean we can dispense with it does it?

For example DateTime and Decimal are structs, and declaring members of these types means the data that comprises them is part of the types physical storage, contiguously laid out.

By allowing users to create their own (blittable) structs allow aggregate data structures to exist that are contiguous and can be passed to native code using ‘ref’ or ‘out’ which then passes a (true) pointer into the native code, this is very fast.

If you need to allow managed code/native code to do a lot of common access to such data then passing refs is very fast indeed.

We have ‘message’ structs here that are pure value types with rather a lot of fields and these can be manipulated as contiguous blocks and accesses rapidly for IO over TCP with no marshaling or serialization this is very fast.

So this justifies ‘struct’ and ‘ref’.

Now as for pointers, sure these should not be used unless there is no reasonable alternative, but you can ONLY use them to point to value types, so if you ever did need to use them, then once again value types (structs) are essential.

Pointers (unlike ‘ref’) can be stored, that is a pointer is is a type and is stored inline as a field when used in a struct. You can’t get a ‘ref’ to a struct and store that, you can only use ‘ref’ when passing to/from methods (you can use TypedReference but lets not get into that).

So pointers allow you to create linked data structures in memory that can be shared/accessed by native and managed code, this cannot be done using reference types.

I can build a large complex tree of structs (that use pointers to point to nodes) in managed memory and then simply pass a ref to the root of that tree into a native method. Providing the structs in the nodes are all blittable, then the native code can do stuff with that data without any marshaling or serialization overheads.

Personally I think there is a fundamental design weakness in .Net’s design regarding how types are defined and instances of them declared, but that’s another story!

Hugh

Reply
Justin

So am I the only one that uses ref more for documentation than for passing structs around? If I am writing or working on an API I know other developers will be working on I’ll use”ref” as kind of a warning that the object they are passing is about to be altered. I don’t usually make a habit of writing my public methods to alter the objects they are being passed, but it does come up sometimes.

Reply
Matt Whitfield

I guess I’m late to the party. But I think sealed has it’s uses. If you want to seal individual methods, that can be very useful. So I’d like to propose that ‘sealed’ is removed from the list and you add ‘new’ (aka ‘screw over polymorphism’) instead

Reply
Kaylan

Justin, you have a way with words and explaining things in such a way that it makes perfect absolute unconditional sense to me. You think like me, you talk, well, at least type like me, and you kinda look like me lol.

Reply
anon

I don’t believe you should be critical toward the concept of using a goto. I feel that you are overlooking one of the most important keywords in software engineering: “intent.” The goto keyword is absolutely awesome in situations where you know it’s futile to wade through the rest of possibilities in a linear function if the intent is to cut to the chase (output an error, and finish the operation, for example; a good way to discover a practical to do this is to work with berkley sockets).

Also consider global variables and the Singleton design pattern. Is that design pattern nothing more than a glorified global? Well, it can be argued either way but ultimately it’s determined by the programmer’s intent.

Then again, I’m making the assumption that your article is intended to be an expression of opinion and I respect your opinion even if I don’t agree with it.

My intent in leaving this comment is to illustrate that it is all to common for software developers to criticize language constructs before spending time to study the reason(s) why such constructs made it past the cutting room floor (so to speak).

Reply
anon

I also disagree with your opposition to the usage of struct. Byte aligned data structures are very friendly to any operating system especially if the data strucure is intended to be used in a container.

A structure whose size in bytes is a power of 2 is much more quickly indexed (mathematically and in context of element access in contiguous memory i.e. an array) than one that is not. Although this also requires the assumption that the target device for what you are creating isn’t horridly restricted with respect to memory.

It’s computer architecture 101.

Reply
anon

And then what about volatile? Maybe I want a volatile ref char to a part of an I/O port (USB, old school serial, that sort of thing.) What’s wrong with point out, plain as day, that the value contained in this thing might not always be under my control?

Reply
nuzz604

The unsafe keyword can be critical when developing systems that interop with unmanaged code. Applying a blanket statement like “you shouldn’t use this” should take into account the small number of cases when you might actually use those keywords. If they were not meant to be used, they wouldn’t exist in the language.

Reply
Andrew

It seems pretty obvious that the audience for this advice is people who don’t know why they are using these things. They all have valid uses, and if you can actually justify them then they are fine and necessary. ref/out with com objects. Structs when you know the use case. Using structs as “lightweight” classes like some people do is totally bonkers. I have seen too much code littered with these where it was absolutely not needed, and the person writing it couldn’t even explain what was really going on.

This is solid advice for 99% of code. If you can’t understand that, wow.

Reply
Edward

A good read. But, why limit yourself to the keywords? How about the silly operators.

?? – the null coalescing operator.
Foo y = x ?? new Foo();

? – allow primitive variables to be null.
int? x = null;

@variables (my favorite idiot operator). For times when you simply must name a variable after a keyword.
int @float = 5; // create an int named float and set equal to 5.

Reply
Koen

With the goto keyword you have a point. For the others, I can’t for the life of me think of reasons to avoid them or brand them ‘bad practice’.

Reply
Michael Starberg

I have read the full article and all the comments up to now, and even if I do understand this is general advice for vanilla application code; I still have issues with every single topic. So I’ll add my commentary:

1) sealed. This topic is not controversial at all. If you are writing leaf application classes then you probably won’t bother with sealing them at all. But if you are writing a public api ment for others, where polymorphism in C# is designed to be non-virtual by default, you will find not allowing sub-classing at all very handy. And I have never heard about the performance argument before. It’s either a virtual call or a direct call. Sure a jitter could figure out if a virtual call could be made into a direct call, but it could discover that without the keyword.

2) goto. True, goto is in the language. But what we get is the standard tantrum on goto together with a cool Dijkstra quote. What is lacking is how the goto is very limited in C#, not allowing for those pesky longjumps that less protective languages allow for. All this while in the end sporting a perfectly good example of when to use goto, calling it silly.

3) unsafe. Red herring here. First a laugh at the keyword and then a link to Eric Lippert talking about something completely different. The day you discover you have dimensional data that you want to treat very fast; you’d be glad the unsafe world of pointer arithmetic was included in the language.

4) ref. Red herring again. The example at the end shows when an instance of a class would be much better. But I see no example of proper use of ref nor how ref differs from out.

5) fixed. This one goes to show that the author is not using unsafe nor threading very often. goto volatile 9 for reference.

6) stackalloc. Another red herring. If you are already unsafe, you would most likely want to allocate memory. I see no mentioning of the framework call to Marshal.AllocHGlobal() that would also be highly useful in this context.

7) unchecked. On the surface this seems like a useless keyword. But I don’t see any reference to the compiler switch /checked. No mention of why it would be a good idea to mark code that will overflow by design (calculating a hashcode for example), with the unchecked keyword.

8) struct. Red herring yet again. Author sees structs getting abused and conclude the keyword should not be used. How about when you have a complex value type used as key in a dictionary? Would you rather use a class?

9) volatile. Non-Sequitur. The author says we should use this keyword, but as this is a list of keywords that we should not use, with unsafe and fixed being banned in the first place, my head spins. goto fixed 5.

10) implicit. A last red herring. We see an example of abuse of subtle implicit casting. But not a word on how implicit/explicit operators should be used. Not using the keyword? You forgot to tell us why.

Reply
AndyD

Have you made a list of interesting things to do with c#?

There are some interesting things people might want to do with unsafe and pointers; like unmanaged memory streams for example, the garbage collector isn’t always brilliant at knowing when it has an opportunity to drop a large amount of managed garbage.

BTW your goto example – how would you get out of those loops? Would you perhaps set a flag then break out of the first loop, and then have a second condition in the outer loop to break out of that too if necessary? These sorts of rigmaroles are why there is a school of thought that goto out of nested loops is a legitimate use of goto.

But its food for thought, I’ve not used struct yet, but I’ll look into it! If it has an advantag ever, I’m going to find it.

Reply
taffer

Ok, it’s a really old post, and maybe the author has a different opinion today but still I thought I answer.

1.) sealed – Michael has answered the main point so I just add some performance part. If you serialize an array or generic collection of non sealed classes, the type of the elements must be stored for each element. For structs and sealed classes this is not needed.

2.) goto – Maybe the only point where you are right. Though sometimes it completely makes sense to use goto inside a switch. It does not make the code unreadable at all.

3.) unsafe – If you can avoid using pointer arithmetic, you are a lucky man. Of course, with IntPtr, Marshal, etc. everything is possible. But if you must not accept the performance of Marshal members, you might need too use unsafe code. In this (hopefully, rare) case the best way is to create a new project, enable unsafe code only for that project and put all of the unsafe routines there.

4.) ref/out – I would say try to minimize them for public members. But there are typical patterns for them, like bool TryGetSomething(out T result)

5.) fixed –
6.) stackalloc –
goto case unsafe

7.) unchecked – hex numbers do not support signs. Consider the following example:
int i = unchecked((int)0xFF000000)
You cannot avoid using unchecked here, unless you use decimal notation instead of hex, but hex is readable in this case.

8.) struct – Fixed size immutable types should be structs. So simple. Struct is often misused even in the framework. For example, System.Drawing.Point would be a typically good example for a struct… provided it wasn’t mutable. A Point with another X coordinate is actually another point. Mutable structs are pain in many cases. But if your (fixed-size) type is intended to be immutable, it is the best approach to define it as a struct. And, of course, use IEquatable, implement Equals/GetHashCode correctly and overload == and != operators.

9.) volatile –
10.) implicit –
You say there are some rare cases where they are useful. Everything can be used badly. Why does it mean not to use them at all? Btw, for references use lock instead of volatile. Implicit: do not use between types into a narrowing direction. So simple.

Conclusion:
Do not use C#. You can do stupid things with that.

Reply
Ben Stabile

[StructLayout(LayoutKind.Explicit)]
public struct FloatBits
{
[FieldOffset(0)] public uint Bits;
[FieldOffset(0)] public float Value;

public FloatBits(float v)
{
Bits = 0;
Value = v;
}

public FloatBits(uint bits)
{
Value = 0;
Bits = bits;
}

public static implicit operator FloatBits(float value)
{
return new FloatBits(value);
}

public static implicit operator FloatBits(uint bits)
{
return new FloatBits(bits);
}

public static explicit operator uint(FloatBits fb)
{
return fb.Bits;
}

public static explicit operator float(FloatBits fb)
{
return fb.Value;
}

public unsafe override string ToString()
{
char* s = stackalloc char[32 + 1];
for (var i = 31; i >= 0; i–)
{
s[31 – i] = ((Bits >> i) & 1) == 1 ? ‘1’ : ‘0’;
}
s[32] = ”;
var result = new string(s);
return result;
}
}

public class UnionExample
{
public static void TestFloatBits()
{
var f = -1f;
for (var i = 0; i < 10; i++, f += i * 0.1f)
{
Console.WriteLine("{0, 12} : {1, 12} : {2, 32}",
f.ToString("F9"), (uint)(FloatBits) f, (FloatBits) f);
}
}
}

Reply
Ben Stabile

Oops, I hit submit too soon. What I meant to do was demonstrate using “fixed” in the struct as an alternative to “stackalloc”. Also, the ” string termination got reduced to ” when I pasted the code.
The results of that demo (with bad formatting)…

-1.000000000 : 3212836864 : 10111111100000000000000000000000
-0.900000000 : 3211159142 : 10111111011001100110011001100110
-0.700000000 : 3207803699 : 10111111001100110011001100110011
-0.400000000 : 3201092812 : 10111110110011001100110011001100
0.000000030 : 855638016 : 00110011000000000000000000000000
0.500000100 : 1056964609 : 00111111000000000000000000000001
1.100000000 : 1066192077 : 00111111100011001100110011001101
1.800000000 : 1072064103 : 00111111111001100110011001100111
2.600000000 : 1076258407 : 01000000001001100110011001100111
3.500000000 : 1080033281 : 01000000011000000000000000000001

In this demo, I am showing that you can easily “simulate” the useful BitConverter.DoubleToInt64Bits(x) and BitConverter.Int64BitsToDouble(x) methods. And the resulting client code can be very clean and efficient (especially for structs).

Without these features you might have to do something like…

BitConverter.ToUInt32(BitConverter.GetBytes(x), 0)

…and that is, in my opinion, pretty ugly! Not to mention the fact that you would then have to include the code to create a bit string, further muddling more important logic.

For someone like me who develops quantitative finance systems, the performance gain of a small

Bottom Line: you can do some fairly useful things with some of the keywords you’ve mentioned. But I agree that you need to thoroughly understand what you are doing!

Reply
Me

Nothing is forbidden in programming, unless the people involved don’t have the skills to maintain/understand it. That’s where the real problem lies.

Programming is engineering and engineering is all about solving problems in the most efficient/suitable way, which by no means should be the most mainstream/safe/clear way there is available.

That being said, I can pick-point situations where using C# properties or not using a goto is the worst practice (performance critical operations as an example). No one can and should categorize things as bad or good without having a clear overview of the context.

We live in a world that is not black and white and everything positive has negative aspects included into it, and vice versa.

And my experience is, that a person that writes crappy code, will continue to do so, even if he avoids using what is considered bad-practices. And the other way around.

All this hysteria over bad and good practices (including silly stuff like counting the lines of methods, searching the code for goto`s, limiting the max. length of variable and method names, etc) is mostly for people marketing useless books of theirs or project managers that have no idea about programming.

If a person writes bad code, these are not the things that make it obvious. I have seen code that followed all good practices and its maintainability was below zero (even the person who wrote it couldn’t follow it…).

Also, if we are to apply the “safeness” rules for JavaScript –for example– we should probably ban the language as a whole (which would be totally OK for me)… However, people are still using this piece of crap, even if using it is like walking on a minefield. And, sure… If you are careful enough and you know what you are doing, you will get what you want working. So, it should not be banned, not even avoided, just I am not sure why browsers still have it as their “one and only” scripting language…

Reply
Eljay

I have yet to find a reason to use these keywords: goto, unsafe, fixed, stackalloc, unchecked, volatile. Not that I wouldn’t use those keywords when/if they are needed, I just have had need yet. So I agree with Justin, de facto.

I disagree with sealed, ref, and struct. Those are fine things to be used, and ought to be used where appropriate in everyday C# code. Both sealed and struct I commonly use, ref is rarely used (but when it is needed, it’s great). I admit that I often lean towards Tuple return type over ref, but that’s just my druthers and nothing against ref.

I agree with Justin on implicit (and explicit). I’ve only seen those abused, and never used correctly. I have never had need to use them (which I would only use them correctly). If I had need, I would use them. I liken the implicit and explicit abuse I’ve seen to improper use of IDisposable I’ve seen.

I like the article. Thought provoking!

Reply
Vandroiy

This post in a nutshell: “This can be abused, so never use it!”

Sorry, but that’s not a valid argument at all. Nor do I think the statements are correct. Especially, forbidding sealed and struct are really bad ideas.

There are more than enough classes that really shouldn’t be inherited; I’d dare say that this is true for the majority of classes. Mark them sealed. If people haven’t heard of composition and encapsulation, they should be off learning, not deriving stuff from other people’s types.

And prohibiting structs is just silly. It breaks interop. Even where they aren’t required, with current compilers, reference types can be a plain waste of performance. Yea, let’s just make our tiny, immutable encapsulation types… independently allocated objects?! For a 2D-vector maybe this can be argued about, but for something like a wrapped integer it’s just nonsense.

Reply
AK

Far too many guidelines expressed as rules here – but then I suppose that’s necessary to attract readers. I have had occasion to use every one of the keywords listed and there are good reasons for all of them to exist. I would agree that they fall into the “advanced” programming category and probably shouldn’t see frequent use, but would contradict your advice and encourage programmers to play with them, understand them and be sure that when they are trotted out, their use is appropriate to the occasion. (Oh, and I too am a business software developer;-)

Reply
ADev

It sounds like a C# hater who recommend Java XD.

Like 99% of the C# devs, I often need to store strings in a dictionary, so implicitly, i have to use :
– A struct keyvaluepair ;
– Unsafe code for generated the string hash ;
– Ref for TryGetValue ;

Occasionaly, I develop a static class, which explicitly means “abstract sealed” (see C# spec).

What is the problem with “goto”. Even the MSDN documentation agrees with you : “The goto statement is useful to get out of deeply nested loops.”.

Reply
taffer

1.) Performance is not just about time; sometimes size matters, too. 😉 If you serialize a collection of a non-sealed type, then the type of each element must be serialized, too. To whatever camp you belong it is out of question that is has no drawback at all if you seal all of your non-public, non inherited classes.

2.) “goto case” is the only way to fall-through switch cases. And it is actually elegant as no additional label is required.

3. 5. 6.) Interop, Bitmap manipulation, performance… oh wait, you already stated performance is not an argument…

4.) “Do not use multiple return values” does not mean “do not use ref at all”. Array.Resize?

7.) Do you want to write the decimal variant instead?
enum MyFlags
{
// …
GenericRead = unchecked((int)0x80000000);
}

8.) Sigh… value semantics require structs. So simple. Do you deserve a smack for mentioning the performance problems of ValueType.Equals? But I go further, you can override Equals for better performance. And implement IEquatable for even better one. Smack me hard for mentioning that.

Performance is sometimes so important that the .NET Framework uses mutable structs, too. See enumerators of List, Dictionary, etc. “Allocating” structs and accessing their members are blazingly fast.

“Besides, heap allocations are so cheap now, right?” – No. By creating a tons of small objects on the heap (eg. in a cycle) you can unnecessarily overload the GC, for example. If you do not pass them around among methods it may definitely worth to use structs instead.

9-10.) No comment

Finally, a _true_ list about keywords not to use. 😉

I.) const (at least public ones) – http://stackoverflow.com/a/56024/5114784
Using a const causes that instead of referencing your const field, the compiler will directly emit its value to each place it is used. Now if you realize that another value would have been a better idea and you change it in the next release and a component uses your assembly, which you cannot recompile… well, that assembly will still use the old value because your const field is never accessed actually.

In public components use readonly static fields instead, unless you are very-very confident…

II.) new (as modifier on members) – Suppressing the warnings about hiding the already defined members of the base type is a bad code smell. If you cannot access the source of the base and you really-really need to reintroduce some members, the you should define a new interface instead. I know there are some exceptional cases but they are still just bad code smell.

III.) __arglist – https://msdn.microsoft.com/en-us/library/8h0f7c37(v=vs.80).aspx
Ineffective, poorly documented, params is better and more convenient. And interoperable varargs can be achieved by other ways, too.

Reply
Dmitri

Apparently Justin forgot to mention also:
– private (protected should do just as fine, why restrict yourself? – same logic as with sealed)
– reflections (if you need to know that value’s type your code is a mess)
– custom attributes (oh my god, you’re definitely doing something wrong)
– extensions (you know if you abuse them, you get confused… see implicit)
– delegates instead of virtual (god created inheritance and overrides, don’t you dare use something else instead!)

I can also guess that he is a proponent of usage of singletons. I used to work with a technical lead of Justin’s persuasion… In addition to these donts the guy also demanded maintaining different code for similar objects and copy/paste. Because this was improving the productivity in lines…

Reply
Ray Koopa

This is a horrible post. First, it should be titled “keywords you won’t need as a beginner” or “keywords you only need in super-special occassions”. There’s a reason for each of those. Take unsafe / fixed / unchecked / stackalloc for example, to strike 4 from the list. The .NET library itself makes quite some use of it, especially when dealing with binary data. Without those keywords, writing more than just bytes to a file would be 5 times slower if you did the benchmarks.

If you really want to complain about keywords, have a look at VB.NET’s idiotic “Optional” or “ByVal” crap. They also have a “reason” to exist, but those reasons are all based on “it was done like this in the past” or “it aids in making stupid VB.NET programmers understand trivial things”. But then you can complain about VB.NET in total 🙂

Reply

Leave a Reply

Your email address will not be published. Required fields are marked *