Stylecop suggest using string.Empty, but String.Empty seems more appropriate

May 23, 2012 at 11:37 PM

Version of StyleCop I'm currently using is v4.4.0.14.  Rule SA1122 says "Use string.Empty rather than "".  However, doesn't it make more sense to use String.Empty rather than string.Empty.  Is this fixed in a newer version of StyleCop?

Thanks!

Coordinator
May 24, 2012 at 9:13 AM

string.Empty is correct.

The rule is:

string not String

int not Int32

etc

May 24, 2012 at 7:25 PM

Can you please elaborate a little on why string.Empy is the correct value to use in this case over String.Empty?

Coordinator
May 25, 2012 at 11:09 AM

Of course. The rule for this is SA1121:UseBuiltInTypeAlias

From the docs:

SA1121: UseBuiltInTypeAlias

TypeName

UseBuiltInTypeAlias

CheckId

SA1121

Category

Readability Rules

Cause

The code uses one of the basic C# types, but does not use the built-in alias for the type.

Rule Description

A violation of this rule occurs when one of the following types are used anywhere in the code: Boolean, Byte, Char, Decimal, Double, Int16, Int32, Int64, Object, SByte, Single, String, UInt16, UInt32, UInt64.

A violation also occurs when any of these types are represented in the code using the full namespace for the type: System.Boolean, System.Byte, System.Char, System.Decimal, System.Double, System.Int16, System.Int32, System.Int64, System.Object, System.SByte, System.Single, System.String, System.UInt16, System.UInt32, System.UInt64.

Rather than using the type name or the fully-qualified type name, the built-in aliases for these types should always be used: bool, byte, char, decimal, double, short, int, long, object, sbyte, float, string, ushort, uint, ulong.

The following table lists each of these types in all three formats:

Type Alias

Type

Fully Qualified Type

bool

Boolean

System.Boolean

byte

Byte

System.Byte

char

Char

System.Char

decimal

Decimal

System.Decimal

double

Double

System.Double

short

Int16

System.Int16

int

Int32

System.Int32

long

Int64

System.Int64

object

Object

System.Object

sbyte

SByte

System.SByte

float

Single

System.Single

string

String

System.String

ushort

UInt16

System.UInt16

uint

UInt32

System.UInt32

ulong

UInt64

System.UInt64

 

How to Fix Violations

To fix a violation of this rule, replace the type with the built-in alias for the type.

 

Jul 3, 2013 at 2:16 PM
Edited Jul 3, 2013 at 5:49 PM
This is not an rational, objective argument for using BuiltIn Aliases instead of the real datatypes, it is simply reiterating a rule that was created with no justification. So far I've only heard dogma related to why this rule exists: because its the way we used to program in C++. I've not heard anyone offer a well reasoned argument for it's continued existence as a feature of a modern language.
Jul 8, 2013 at 12:54 PM
DRAirey1 wrote:
This is not an rational, objective argument for using BuiltIn Aliases instead of the real datatypes, it is simply reiterating a rule that was created with no justification. So far I've only heard dogma related to why this rule exists: because its the way we used to program in C++. I've not heard anyone offer a well reasoned argument for it's continued existence as a feature of a modern language.
Just disable the rule and that's all.
Jul 8, 2013 at 3:11 PM
Edited Jul 8, 2013 at 4:39 PM
I'm actually a big believer in the principals of StyleCop. What good are a set of universal rules if you pick and choose which ones you want? Sure, I've had to change my company's coding style to conform to StyleCop settings, but the ROI is that we don't have to spend countless hours arguing over style, the ordering of members, how to create a backing store, indenting, etc. This particular issue - SA1121 - is very important because this is the only one of StyleCop's dozen's of rules that is irrational and panders to the users of an obsolete language.
Jul 8, 2013 at 3:48 PM
There are pros and cons for using either one of the two (or even a mix), but IMO using the CLR type "String" would be the better alternative.

Nonetheless, since there are good arguments for both, I think this is one of those cases where you should not try to enforce one over the other.

It would probably be best, if there was no such rule. Because in general I totally agree with DRAirey1: StyleCop rules should be universal and this one is not.

Knowing that we already have it and that it won't get deleted, I'll have to disable it.
Jul 10, 2013 at 10:25 PM
berntie -

The main argument for the rule to be as it stands now, and part of why I'm glad it is the way it stands now, is that enforcing String.Empty would mean that every C# file that used String.Empty would need to also be forced to have a "using System;" - which is often unnecessary.

The only way to avoid this as a general rule is to use the language alias (string.Empty), or force a fully qualified name (System.String.Empty), and I find the latter obnoxious personally...
Jul 10, 2013 at 11:12 PM
Edited Jul 11, 2013 at 6:50 PM
Reed -

Seriously? That's it? Count up the number of C# modules that don't have any 'using' statements in them. Divide that by the total number of C# modules there are. You should have a number that's close to your odds of winning the lottery tonight. Every practical C# module is going to reference a namespace associated with a library. Adding namespace references to a module is such a common action that ReSharper and Visual Studio both have commands to add namespaces automatically.

Unlike C and C++, C# was designed to have extensible data types. This is a very powerful concept that separates C# from the older, inflexible languages. That means there is no practical difference between a 'System.Double' and a 'MyLib.Triple' to the compiler. Concepts like 'built-in' data types belong to those older languages. They were conceived as an afterthought to speed adaptation by the C and C++ programmers. 'int', 'string' and 'double' are completely disposable features of the C# language and grown-up engineers should be able to code without training wheels.
Jul 14, 2013 at 10:16 PM
They are not training wheels. They are part of the C# language specification.
Jul 14, 2013 at 10:43 PM
Edited Jul 15, 2013 at 3:03 PM
The reserved words were put there for programmers who were not able to comprehend that a language doesn't need a fixed set of data types. Falling back on 'they're part of the C# language specification' is dogma. The specification was put together by a committee that realized there was going to be resistance by 'C' and C++ programmers if they weren't able to find familiar concepts in the new language. Why did this committee create a 'double' reserved word but not a 'datetime' reserved word? They're both 'primitive' datatypes found in the same library. The only reasonable answer is this: 'datetime' wasn't required as a training wheels for 'C' and C++ programmers.
Jul 19, 2013 at 1:09 PM
I've been programming a long time and I don't see the aliases as training wheels, but more of a convenience and I would support a DateTime alias if DateTime had literals in C#. While I did do a lot of C/C++ programming I've also done a fair bit of SQL, VB, Python, Lua, C#, Java, JavaScript and other languages. Aliases aren't the enemy. For many they make for easier to read code when you have colored highlighting on. And while you may not see them as special, they are, in fact, special given that they support literals and form the primitives of the language and one or more is bound to come up in your program even if all those other classes aren't.

That said, I would like the rule revised so that if the base type is included in the name of the function is it tolerated in the return type or parameters. E.g.

public static Int32 ToInt32() { }

The above should tolerate the Int32 return value. That's the one place where I disagree with the rule.
Jul 19, 2013 at 1:59 PM
You are just proving my point. You are a C/C++ programmer and you believe that a language must have primitive data types because that's what you've grown up using. I wouldn't expect a C/C++ programmer to understand that this is an obsolete concept any more that I would expect a BASIC programmer to understand that a programming language doesn't need line numbers.

If you want to try the color highlighting argument, there is this: there is NO reason that a statement containing a double declaration should be a different color than a statement containing a System.DateTime declaration. It is confusing, arbitrary and only the most devout 'C' programmer sees this as aesthetically pleasing.
Jul 19, 2013 at 5:49 PM
Edited Jul 19, 2013 at 7:27 PM
Um, I did BASIC programming and I knew line numbers were pretty dumb and was glad to ditch them. You're not going to have a lot of success convincing the community to come over to your side by insulting them all. It doesn't matter if you're right if no one will listen to you. You don't think people loved ditching line numbers. Find a way to understand why people prefer the alias over the raw type and you might be able to address their issues. Until then you're just yelling at the wall.

But since I'm already speaking, I'll give you a little hint. The aliases are partially better because they are lower case. If you type a lot in environments that don't have auto-complete, that small amount of less typing is beneficial. Also it's done for portability. There are a lot of C/C++ algorithms that can be copied over to C# without a lot of changes -- which is beneficial.

I stopped programming seriously in C/C++ when .Net hit pre-release status and have been a hard-core C# programmer ever since and your fallacious arguments relying on your perception of my motivations doesn't help your argument. You have presented your argument and some remain people here remain unconvinced. You can continue to insult people and repeat the same argument over again or you can actually engage in a dialog and help come to some resolution.
Jul 19, 2013 at 8:15 PM
Edited Jul 20, 2013 at 5:38 PM
If you want a logical, well constructed argument, try this thread:

https://stylecop.codeplex.com/discussions/448862

In the mean time, I've read all the arguments in favor of using the aliases and all of them reduce to: "I have legacy code/I learned to program this way". Your additional arguments are absurd: we should use 'int' for the programmer(s) who doesn't/don't have autocomplete and can't be bothered typing the additional two characters to make it 'Int32', and for porting legacy code. The last one may be a valid marketing concern, but these are poor decisions for the design of a modern programming language.

An alias is a "false or assumed identity". It is, by definition, designed to obfuscate. The real data type is an System.Int32 and the C# aliases are designed to hide that detail for people who can't understand that there are no built-in, hard-coded data types in C#. I completely understand why the authors of C# included them, but those reasons were based on marketing to a generation of 'C' programmers and shouldn't be encouraged by StyleCop.

I'd love to hear some reason that doesn't come back to "This is how I learned to program". Your arguments are based on dogma, not logic or sound design, and that is why I appear to have so little patience for them. They belong to the same category of arguments that BASIC programmers make for using line numbers.
Jul 22, 2013 at 1:19 AM
My take has always been that int was preferable to int32, and long preferable to int64, because using the framework provided CTS alias types was introducing 'low-level details' to your otherwise pure managed code. In general I've regarded int and long as a "general range" of values, rather than a hard-set alias to the system types. Typically the idea that they happen to have a specific bit-width simply wasn't relevant, and not typically helpful for readability.

My more prevalent reason for using the language-defined aliases is as a readability "marker" for CLS-compliance. If I can create a structure using C# language types, I will be CLS compliant. As a result if I try to use the aliased types where possible, I can identify non-CLS compliant code by the presence of other data types. This may not be the strongest argument but IMO types like Int32 and Int64 and UInt32 and whatnot will stick out from the aliased types because they are textually 'louder', which could be considered to support a readability rule.

From what I was able to learn, the primitive aliases such as int and long are not aliases to System.Int16 and System.Int32, but rather aliases to the CTS types. System.Int16, for example, represents the CTS int16 type; System.Single represents the CTS float32 type, and so on. From what I can gather it seems to be that the C# int and long types are compiled as CTS types, and those CTS types are decompiled by decompilers to be System.Int32 and System.Int64.

That is what I was able to learn on the subject regarding CTS types, the C# language primitive types, and the 'primitive types' provided by the CLR, (mostly through ECMA-335). I'm not sure how much is entirely relevant or even correct, though. Please point out any appropriate corrections to any misunderstandings or misconceptions I may have :)
Jul 22, 2013 at 3:01 PM
Edited Jul 22, 2013 at 3:34 PM
Mr. Programming, I'm sorry, but little of what you say makes sense. First off, a 'uint' will generate the same CLS-compatibility warning as 'UInt32'. So I'm not sure I understand how the syntax coloring is any help one way or another or even what you mean by a "C# language type" (there are no C# language types; that is a 'C' concept).

Secondly, CLS-compliance is all about making sure that different programming languages can interact. It's mainly about naming conventions, calling conventions and avoiding certain data types in publically visible method calls. CLS-compliance is an argument FOR using System.Int32, not against it. F#, C#, Visual Basic and PowerShell all recognize and understand what a System.Int32 is. Only C# understands what an 'int' is. I have already made a case for CLS-compliance as a reason to drop the aliases but was told by one of the moderators that StyleCop is a compiler style checker, not a CLR checker, so I haven't pushed this part of the argument.
Jul 22, 2013 at 4:12 PM
Edited Jul 22, 2013 at 4:22 PM
Mr. Programming, I'm sorry, but little of what you say makes sense. First of, a 'uint' will generate the same CLS-compatiblity warning as 'UInt32'.
Ahh... I had forgotten about the existence of uint and ulong type keywords. I should be more specific, in that part of it is a subjective enforcement on my part to use the language type keywords to indicate CLS compliance. Primarily, I use it personally as an indicator for segments that use unsafe blocks and P/Invoke. For P/Invoke signatures I use the System types, for example, as well as structures to be used through P/Invoke, because in those cases the size of a variable is often important. Of course if I was to use StyleCop on those segments, this readability rule would probably trigger, so in that sense I agree.
Secondly, CLS-compliance is all about making sure that different programming languages can interact. It's mainly about naming convensions, calling convensions and avoiding certain data types in publically visible method calls.
CLS compliance, from what I can tell through the aforementioned ECMA specification, includes references to the usage of CLR types. System.Int16 from what I can gather and learn through research and experimentation is not what code compiled using a short end up as, but rather the CLR/CIL type, int32. float becomes the CLR float32 type in IL, with the System namespace value types serving primarily as a way of boxing those CLR internal data types. I'm not certain of this so I intend to perform further tests and investigations when I have time, since this is an area for which it is difficult to find any technical information on the details. I suspect my conclusions were incorrect and intend to falsify them to show that type keywords are in fact direct aliases for the System namespace types.
F#, C#, Visual Basic and Powershell all recognize and understand what a System.Int32 is. Only C# understands what an 'int' is.
Very true. Certainly a legitimate consideration. But the rule is listed as a "readability" rule, as well. I can understand that Int32 can be less readable than int, simply because the type has information that might not be very relevant to the logic in question.
I have alread made a case for CLS-compliance as a reason to drop the aliases but was told by one of the moderators that StyleCop is a compiler style checker, not a CLR checker, so I haven't pushed this part of the argument.
Well in fairness I don't actually use StyleCop myself, and a link to this thread appeared in my inbox through a mailing list. Even so, I use the C# keyword types myself though. (I did not come from C/C++ FWIW) From my perspective there aren't any particularly strong reasons to use the Boxing Value types themselves, so in that sense I'm somewhat of the opposite opinion as yourself.

I imagine that in this case the rule is in place to prevent the mixing of the language types with the types defined in the system namespace. If they had gone with the System namespace types in the rule, I don't imagine that there wouldn't be a thread titled "Stylecop suggests using String.Empty, but string.empty seems more appropriate" here, so it's more a case of the choice having to be made for the readability consideration but there would always be a set of users that would not like whichever choice was made.

The only thing I can think of would be a rule that, rather than unilaterally requiring one or the other, instead simply flags components (methods, classes, or assemblies) that happen to mix the C# keyword types and the equivalent types in the System Namespace and simply requires the choice between one or the other. I'm not sure if that is much of a solution, though.