Compiler, It Hurts When I Do This

July 26, 2006

Here's a question that recently came up on an internal mailing list: how do I create an enum with a name that happens to be a c# keyword?

I immediately knew the answer for VB.net; you use brackets to delimit the word.

    Public Enum test
        [Public]
        [Private]
    End Enum

    Sub Main()
        Dim e As test = test.Private
    End Sub

A little internet searching revealed that such things are called escaped identifiers, and the equivalent in c# is the @ character.

    public enum test
    {
        @public,
        @private
    }

    static void main()
    {
        test e = test.@private;
    }

They do work the same, but they don't look the same. In c#, you have to type the unwanted escaped identifier every time you use the enum, and the enum even shows up with the @ prefix in intellisense. However, if you echo back the enum value, it will be "private", and not "@private", as expected.

However, after spending 30 minutes researching the answer and playing with the results, I began to wonder if the real answer to this question should be another question: why do you need to do this? At some point it all becomes a little ridiculous. What's next-- an enum named "enum"? A variable named "variable"?

Stop me if you've heard this one before:

A man goes to a doctor's office. He says, "Doctor, it hurts when I raise my arm over my head."

The doctor replies, "Then don't raise your arm over your head."

If the compiler is telling you it hurts when you do something, maybe you should stop doing it. Just something to consider before merrily swimming your way upstream.

Posted by Jeff Atwood
45 Comments

i definitely agree with your assessement of: don't do that. on a funny note, i have seen lots of things like the following:
int eger;
var iable;
bool ean;

dinah on July 26, 2006 2:38 AM

I agree that you shouldn't be naming properties and method names the same as keywords. However, this is not a simple problem with a cross language VM platform. If the compiled objects are language independent and each language has different keywords, then you *will* get conflicts as new languages are ported to the platform.

Damien on July 26, 2006 2:43 AM

how about:
public enum test
{
publ1c,
pr1vat3
}

(I _knew_ l337 speak had it's place in the world!)

also, to quote TheDailyWTF on interested variable names:

double cheeseburger;
char broiled;
long time;

;)

Ben Scheirman on July 26, 2006 2:48 AM

also, consider that

Public and Private wouldn't cause any fuss because it differs in case. So you'd avoid the @ and follow better naming conventions at the same time.

Ben Scheirman on July 26, 2006 2:50 AM

better naming conventions

I don't know that I would call two things that differ only in the case of the first letter a "better naming convention".

That's an accident waiting to happen.

Jeff Atwood on July 26, 2006 2:52 AM

If the idea is to make code, specifically variable names, self-describing, then this really isnt all that unreasonable.

Lets say, for sake of argument, I am working for an agency that specializes in software for schools.

Some potential attributes for a school are: public, or private.

An enum is a reasonable choice in this instance. Sure, I could use PublicSchool, or PrivateSchool, instead, but that is potentially redundant.

Elliot Rodriguez on July 26, 2006 2:53 AM

What Damien said. You've got a good example in the first code snippet there - the "Dim" keyword in VB.

"Dim" is not a keyword in C#. Creating an enum member called "Dim" in C# is perfectly valid, and doesn't hurt in the slightest, so there's no reason not to do it. If you want to access the code from VB.NET though, you need to know how it's possible.

This goes both ways, and is not guardable against in a general sense as there's no way of knowing what languages will get ported to .NET in the future (*shudder* - perl.net?), so it's impossible to enumerate all the keywords that *might be* used by *all* of them.

Adam on July 26, 2006 2:54 AM

"Dim" is not a keyword in C#. Creating an enum member called "Dim" in C# is perfectly valid

True, and worth thinking about. But you can use the [] or @ escaped identifiers to get around that edge condition.

is not guardable against in a general sense as there's no way of knowing what languages will get ported to .NET in the future

Well, right, so why worry about that?

I say focus on today's problems today (eg, Dim) and deal with future problems when they actually arise.

Jeff Atwood on July 26, 2006 2:57 AM

"I don't know that I would call two things that differ only in the case of the first letter a "better naming convention". "

Yeah if you were naming two variables, then definitely I agree with you. But we're talking about a C# keyword and an improperly cased enumeration (obviously judged by naming standards). What's the problem with having an enumeration like this:

public enum Destination
{
Home,
Store,
Void
}

or

public enum UnionMemberType
{
Regular,
Delegate
}

none of these stand out as "wrong" to me, the casing differentiates it and follows my naming standard.

Ben Scheirman on July 26, 2006 3:04 AM

A man goes to a doctor's office. He says, "Doctor, it hurts when I raise my arm over my head."
The doctor replies, "Then don't raise your arm over your head."

"But doctor, we need the eggs!"

Oh, sorry, wrong punch line.

Darrin on July 26, 2006 3:12 AM

" "Dim" is not a keyword in C#. Creating an enum member called "Dim" in C# is perfectly valid

True, and worth thinking about. But you can use the [] or @ escaped identifiers to get around that edge condition. "

But it's interesting because it means the keyword limiter is embedded in the compiler itself and not in the CLR.(if you can create enums of VB.NET keywords in C#)

Scott on July 26, 2006 3:26 AM

On a project a couple years ago our primary domain concept was an "Event," so of course we named the class Event. Oh, that hurt.

Jeremy on July 26, 2006 5:04 AM

public enum test
{
IsPublic,
IsPrivate
}

public enum test
{
is_public,
is_private
}

Dim e As test = test.IsPrivate
Dim e As test = test.is_private

Matt Trout on July 26, 2006 5:52 AM

Try naming conventions in SQL that can contain blanks? Order ID, Key to name a couple are pretty common column fields. Its just always easy as has been said above, to have variable names and enums that make sense within the context of things yet violate the keyword rule.

If a complier is smart enough to handle scoping and multiple iterations of a call and keep track of the scope of those iteratated variables that it would be able to hanlde something like keyword variable names. Wouldn't it just be an extension of the scoping?

Mindfulgeek on July 26, 2006 6:01 AM

Good thing about having English as second language: you make enums using words in your first language. In my case, "Portuguese".

public enum teste
{
privado,
publico
}

;)

Jonas Borges on July 26, 2006 6:16 AM

If you generate C# from an XML Schema using xsd.exe, and it runs into entities with reserved names, it prefixes the class names with @.

mrcllv on July 26, 2006 6:19 AM

Maybe it helps porting code in which those weren't keywords. Or somehow helps with autogenerated code. Or maybe an escape route for dealing with conflicting future keywords added to the language.

pUnk on July 26, 2006 10:00 AM

Indeed, why do I have to do this ?


But I will follow another path than you. Your first example was :

Public Enum Test
Public = 1
Private = 2
End Enum

The compiler will say that you can't use a special keyword inside Enum. But why ? My enum's names will always be prefixed with the enum :
Test.Public
Test.Private

Can someone see where is the keyword ? All I see is an Enum identifier, followed by a name.

My conclusion is that the compiler is baddly written, because he can't make the difference when "private" is a modifier or when it's an enum name.

Florentg on July 27, 2006 2:42 AM

Yes, why doing it ?

Good programming practice is readability of the code so, even if you hack the compiler to use language keywords, why just making this confusion ?

There is a plenty of words outside there .. use it !

Stefano on July 27, 2006 3:33 AM

Hi,
just a bit of trivia...that On Error Goto Hell IMHO comes from an old Visual Basic book from a publisher called The MandelBrot set(AFAIK).

Something else - sometimes, the compiler says that sth hurts but you cant do anything against it. Thats a very popular problem for the Palm OS, e.g.!

Best regards
Tam Hanna

Tam Hanna on July 27, 2006 4:17 AM

Stefano : I fully agree
Florentg : in fact the compiler obey spec of the language that forbid the use of keywords as identifiers. So if this language don't fit your nedd choose another one, maybe ML or haskell got what you want.
By the way thinking that what you think at the first time is the solution and the whole word should adopt your way of thinking is a bit arrogant to me. I prefer learning from others, try to fix what's broken and then enlight.
Jonas Borges : yeah i agree i first hiink it's a nice solution. but one day I had to maintain an application made by a romanian guy... since then even if english is also my second language, i prefer to have english name for identifiers.

then public / private is valid for a school but a bit limited, here we have public funded/ half-public funded/ private funded/ private funded with public agreement/ not even mentionnd if the school is religious or not ...

peace

Steve on July 27, 2006 6:11 AM

I think the readability factor is a deciding factor here.

My background is in VB (3, 5, 6, now .NET). I am also familiar with C# and Java (but only for hobby applications, nothing big).

I am used to case insensitivity. I frequently forget that in C#, Public and public are different. (of course, the compiler reminds me, and the occurances are less frequent now).

In many productions enviroments, a new programmer is hired, who may not have your particular skill set. When using keywords as variables, and just make them "different" by case, it can be a nightmare for the new person if they are not used to your convention.

Why amplify the problem? Just use a different word... like the IsPublic option (using a 2nd language triggers the same issues as case, if the folks reading don't have your 2nd language knowledge).

Eric D. Burdo on July 27, 2006 6:18 AM

@Steve : sorry, I didn't want to be arrogant :) Just wanted to raise some questions. I don't want the world to adopt my way of thinking...

Florentg on July 27, 2006 6:23 AM

This is needed when you add new keywords to the language like the upcoming LINQ which makes a half dozen common english words keywords.

When experimenting with the new LINQ Complier I found dozens of instances where I had to use the [] (I used VB.NET) because variable or enums with names like SELECT and ORDER were now conflicting with keywords.

Rob Conley on July 27, 2006 6:26 AM

maybe if you don't like your teammate who is developing in a c# module (yours is vb.net) and you want him to be puzzled.

the main purpose of the @ is really for c# coders using a non-c# library/assembly

jokiz on July 27, 2006 6:34 AM

My current project is a forensic application that is based around the concept of a case. Of course case is a restricted keyword in c++ so i have to spell it kase everywhere it's a function. The class is Case so no problem but the misspelling is tedious.

As languages get more and more keywords it's nice not to have them get in the way in contexts where the keyword is inappropriate anyway.

Max Howell on July 27, 2006 6:45 AM

I agree that it is not the best choice to use keywords, I just don't see why the compilier needs to have that restriction.

As Max points out as 3GL and 4GL become more and more powerful, they have more keywords and our choices become less.

Mindfulgeek on July 27, 2006 6:52 AM

Nice post Jeff,
It reminds me of a time a while back when I was giving a Java tutorial, a student had written coding using the ugliest possible syntax. It had

i+=i++;

I thought about it for a while, and then asked the class what value they thought 'i' should hold. The only 'correct' answer I got was

"What the hell does it matter? You should never see that code to have to be puzzled by it!!!"

It's like asking what does ink taste like. You don't know, you don't want to know, and if you're in a position where you have to find out, then you're already in all sorts of trouble.

Des Traynor on July 27, 2006 6:55 AM

This is definitely thedailywtf.com material. Who in their right mind would create a variables that use the keywords.

They should be lined up and be shot...

Dr. Confused on July 27, 2006 8:03 AM

@Dr.Confused

Sometimes you need some identifier which happens to exists as a langage keyword. It happened to me several times, unfortunately :( Take Jeff's example, sometimes a "public" or "private" makes sense :(

Florentg on July 27, 2006 8:37 AM

Behold this syntactically valid VBScript For ... Next loop:

For [Step Step [Step [Step] = [Step [Step [Step [Step] to [Step [Step [Step Step [Step] Step [Step [Step Step [Step Step [Step]
[Step [[Step Step [Step]([Step Step [Step [Step])
Next

Mat Hall on July 27, 2006 9:41 AM

Crazy... didn't know about "escaped identifiers"

David Grant on July 27, 2006 9:48 AM

I would say hungarian notation solves this issue most of the time. Just tack the right stuff on and you shouldnt have keyword issues.(might want to add namespaces if your really going for platform indipendance compiling). We had a similar issue at my current job, past code was in pascal, and used keywords of C++... when we converted the code to C++ we added hungarian notation.

Jack Stephani on July 27, 2006 10:27 AM

@Florentg:

Sometimes you need some identifier which happens to exists as a langage keyword.

No you don't. Ever. I'm not aware of any widely known language that has such a small vocabulary that you would _have_ to use a programming language keyword as an identifier.

For example, in Max Howell's kase g, I'd use something like CurrentCase, PreviousCase, ThisCase, TheCase, etc. rather than forcing myself to type 'kase' all of the time.

KenW on July 27, 2006 10:35 AM

Two comments:

C# also has contextual keywords (get, set, partial,value, etc.) which aren't reserved words. This approach makes parsing more difficult but reduces the number of potential conflicts. Perhaps LINQ support in C# will go this route?

Some older languages such as PL/1 didn't have reserved words. It was perfectly legal to have variable names such as if, else, raise, etc. The names are all contextual. But this makes writing the parser a brutal exercise.

Bob Congdon on July 27, 2006 10:56 AM

It's like asking what does ink taste like.
You don't know, you don't want to know, and if
you're in a position where you have to find out,
then you're already in all sorts of trouble.

Come now. In the Cause Of Science, tasting a bit
of ink does even wiggle the gross-o-meter:
http://www.sjgarchive.org/library/text/timeArrow/p0099.htm

fred on July 27, 2006 11:46 AM

From a language design perspective, the following approach that comes to mind to solving the problem of reserved keywords coming into conflict with names during cross-compilation: have all language elements in a namespace (like, for example, xslt). This namespace could be 'invisible' by default, i.e. not required to be specified. When a program was cross-compiled, variable names, class names, etc., could be explicitly related to the global namespace in order to disambiguate them from language keywords. For example (roughly imitating c++ namespace syntax, although of course c++ would not allow the following code):

class Visibility
{
private:
boolean ::private;
};

Because the private variable would really be cpp::private, it would not conflict with ::private, since it is in a different namespace.

Skarl on July 27, 2006 12:32 PM

I was building classes that need to be serialized to xml that validates against a strict schema.
The schema specifies several attributes for modification details, one of which is "Status", which is defined as an xsd enumeration of "new", "delete", "revise".

Creating an enum of

enum StatusEnum
{
@new,
delete,
revise
}

means I can read and write the xml using Enum.Parse() and status.ToString(), and ensure that the object can only ever contain one of those values.

Edward on July 27, 2006 1:29 PM

I'd like to propose that the context of the enumeration is something to consider.

If you're doing this as part of a well-thought-out design, that's well-planned, well-tested, documented, and isolated, then it's probably not a coding horror. (I'll show an example in a minute.)

If, however, you're doing this as a one-off (just one or two enums in your system), then it's probaby a real problem waiting to happen.

One time you might reasonably see lots of enums that contain keywords is when you're dealing with software that parses or generates code. This would be one of those cases in which using keywords as the names of enum values does NOT constitute a coding horror.

I've got some code I've written inhouse myself that does this very thing . It's a tool that generates data layer classes for your database, so that you don't have to write them. It uses enumerations like this:

Public Enum Visibility
[Public]
[Protected]
[Private]
End Enum

What's nice about it is that you can use reflection to get the name of the enumeration value and us that to put in the code, rather than a large, cumbersome Select Case structure.

The code is clean throughout the system; it's been tested rigorously, and has been running for two years. It's generated millions of lines of code. And it is a breeze to maintain for the developers because the code reads simply.

Some would contend that I should have used a different value, such as IsPrivate, IsPublic, and IsProtected. That's certainly a possibility. But in a system like this, where I am using reflection to obtain the name of the enumeration's value, it would have meant adding additional code to strip out the "Is" prefix. That would have meant two things: Code bloat and performance reduction all to satisfy a naming convention. In my book, that's an unacceptable tradeoff.

Just my two cents.

Mike on July 28, 2006 5:28 AM

There is a very easy answer

You cant! Not strictly true but it should be. It is idiotic to want to do this. It is like allowing spaces in fieldnames in databases or allowing fieldsnames to be reserved words, they have to be surrounded in [] if thats the case dont do it, and our languages shouldnt let us do it. It's just making bad code.

Toby Allen on August 3, 2006 3:44 AM

class Visibility
{
private:
boolean ::private;
};

My God, it's full of colons.
I admit it's a clever idea to solve a language problem, but can you imagine trying to maintain code where someone's done this?
Find *and* Replace.

deworde on November 20, 2007 5:42 AM

And, BTW, that doctor/patient joke... isn't a joke.
I worked for a while with my father, an ophthalmologist. He had more than one patient who came in complaining that their eyes started to hurt if they try to look strongly all the way up, or up left/right, and keep at it for more than a few seconds.
The reply, the only possible reply, was of course a "then don't do that".

As for the matter on hand, to Florentg, doesn't C# allow to pass/assign/whatever just enum values not prefixed by the enum name?
I don't have C# experience, but C++ allows to do it just fine, and I expect it will carry.
So if you're allowed to write code conceptually like:

Test a;
a=Public;

then you still have the problem. Allowing it when the name isn't like a keyword, but not when it is, will be an inconsistent behaviour. If the language allows not to prefix the name of the actual enum, it then makes sense not to allow any internal names that match with keywords.

Yaron on February 6, 2010 9:51 PM

Delphi.Net has a different syntax too: "". For those who've come from C/C++, you can imagine just how confusing/annoying this is. Of course, they couldn't use "@" like C#, because "@" actually means the same thing in Delphi that "" means in C++! And you had to use this all the time, since Delphi's internal keywords (like "string") would conflict with CLR classes.

Delphi's not case-sensitive either, so some of the comments here wouldn't have worked. Ultimately I think that was a good thing, as it forced developers to think of better, non-conflicting names. In the case of enumerations it was usually a hungarian-ish notation, which wasn't necessarily so bad because there was almost no chance of conflict, it was easy to recognize the enumeration type, but also much more compact than "GenericUriParserOptions.DontUnescapePathDotsAndSlashes".

Case-sensitivity opens the door to some very bad coding practices which I admit I haven't been completely immune to, not least of which is naming parameters/locals as the lowercase version of its class ("User user"). Just because you *can* do something in a language doesn't mean you *should*, and giving classes/enumerations the same names as keywords (capitalized or not) is, IMO, one of those bad practices that shouldn't be used unless there is a very good reason to - which there rarely is.

Aaron G on February 6, 2010 9:51 PM

I think Max Howell had a nice example of how work around the keyword issue. I was thinking forensiccase instead of kase, but the point is, you can always find a name that works.

I think the problem is allowing the name with the brackets or with the escape identifier (@). In my opinion, why bother, it is sure to cause some confusion somewhere down the line. Maybe its better if they were not allowed to begin with.

Jon Raynor on February 6, 2010 9:51 PM

Mat-

You forgot the error handler:

On Error Goto Hell

For [Step Step [Step [Step] = [Step [Step [Step [Step] to [Step [Step [Step Step [Step] Step [Step [Step Step [Step Step [Step]
[Step [[Step Step [Step]([Step Step [Step [Step])
Next

Exit Sub

Hell:

'Welcome to the 7th layer of VB Step Hell

Jon Raynor on February 6, 2010 9:51 PM

The comments to this entry are closed.