Related
The type system violation which I talk about - is when emulating unions.
Why is it allowed in safe context?
It allows you to handle value types, as different value type - as you would achieve with:
float f = 2.5f;
int binaryIdenticalInt = *((int*)&f);
It allows you to reference an object of type X, as it was of type Y, EVEN WHEN THERE IS NO RELATION BETWEEN THOSE TYPES.
It allows you to create types which the CLR won't even load (if at least one of overlapping fields is a reference type, and at least one of them is value/pointer type - the CLR would refuse to load it). I would expect the C# compiler to be more picky about what it allows, than the CLR. not less.
So, why the compiler allow such things in safe context in the first place? Why doesn't it require unsafe context for types with explicit layout, which have overlapping fields?
I hope someone out there has an answer - because it has to be interesting.
Examples (all compiled without unsafe block, nor even unsafe switch):
[StructLayout(LayoutKind.Explicit)]
struct ValueUnion
{
[FieldOffset(0)]
public int i;
[FieldOffset(0)]
public float f;
}
[StructLayout(LayoutKind.Explicit)]
struct ReferenceUnion
{
[FieldOffset(0)]
public string str;
[FieldOffset(0)]
public Stream stream;
}
[StructLayout(LayoutKind.Explicit)]
struct CLRWontLoad
{
[FieldOffset(0)]
public string str;
[FieldOffset(0)]
public IntPtr ptr;
}
Let me answer some slightly different questions.
Does using the explicit layout attribute allow violations of type safety without using the unsafe keyword?
Yes. That's what it's for.
What knowledge of the FieldOffset attribute does the compiler have?
The compiler verifies that the FieldOffset attribute is not on static / const fields and that it is consistent with the StructLayout attribute. It does not check anything else about the validity of the attribute.
Why does the C# compiler not detect a potentially unsafe usage of the attribute and require the unsafe keyword?
That's a feature. In order to be used by you, a feature must be thought of, designed, specified, implemented, tested, documented and shipped to customers. This feature was thought of. It was not designed, specified, implemented, tested, documented, or shipped, and therefore there is no such feature.
That's an unsatisfying answer.
My advice is to not ask "why" questions on StackOverflow. "Why" questions are vague, and therefore you often get unsatisfying answers. "Why not" questions are even harder to answer satisfactorilly because they have the presupposition that there needs to be a good reason for the world to not be a way that it isn't.
OK, let me rephrase. If this feature were pitched to the compiler design team, what pros and cons might they consider when deciding whether to proceed with the feature?
Pro: the code can clearly be used in an unsafe manner, and so should require the unsafe keyword to allow it.
Con: the unsafe keyword is there to prevent accidental use of dangerously unsafe features, feature which four decades of C has shown us that even expert programmers make hard-to-find mistakes. There is no way to accidentally use the struct layout attribute. Someone who uses this attribute can be assumed to know precisely what they're doing, and have a good reason for what they're doing.
In my opinion, the cons outweigh the pros here. The feature would be a very small benefit for a moderate cost.
Remember, every feature implemented means another feature on the list not implemented, because the budget is finite. I would not want to do this weak feature and have to cut a feature that actually benefited developers.
Has the team considered this feature and rejected it on these grounds?
Yes. See
http://connect.microsoft.com/VisualStudio/feedback/details/357828/using-explicit-struct-layout-causes-compiler-to-produce-unverifiable-code
This somewhat inevitably ends up as a circular explanation. It allows you to use unions to violate type safety because that's what you use unions for. It cannot omit the feature because you can't write decent pinvoke without it. The winapi in particular is rife with unions. And pinvoke is not unsafe, it is merely unverifiable. C# is a pretty pragmatic language, if you want to shoot your leg off then you're entitled to.
It is not otherwise a security hole. What the CLR truly cares about is verifiable code. The C# unsafe keyword merely has overlap, C# code without the keyword is not automatically also verifiable. With pinvoke being the most obvious example. The CLR source code explains it pretty well in a comment. From clr/src/vm/class.cpp, MethodTableBuilder::HandleExplicitLayout() function:
// go through each field and look for invalid layout
// (note that we are more permissive than what Ecma allows. We only disallow the minimum set necessary to
// close security holes.)
//
// This is what we implment:
//
// 1. Verify that every OREF is on a valid alignment
// 2. Verify that OREFs only overlap with other OREFs.
// 3. If an OREF does overlap with another OREF, the class is marked unverifiable.
// 4. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
//
"OREF" means "Object reference". It is rule number 3 that puts the kibosh on writing truly unsafe code, unveriable code can only run in full trust. Rule number 2 rejects your 3rd example. That one has fundamental cooties because the GC cannot possibly guess if the object reference is valid so cannot keep the object alive.
There's more code that deals with explicit layout, it for example also calculates the minimum trust based on the trust of the participating field types. You can have a look-see in the SSCLI20 distribution.
Oh, now you've added examples.
The compilers allows it because this code is safe. Almost everything you do with unsafe code can be done with safe code. That's why nobody hardly uses unsafe code.
C# also allows you to serialize one type and deserialize it into the other. Safe doesn't mean bug-free.
It looks strange especially for C++ developers. In C++ we used to mark a parameter as const in order to be sure that its state will not be changed in the method. There are also other C++ specific reasons, like passing const ref in order to pass by ref and be sure that state will not be changed. But why can't we mark as method parameters const in C#?
Why can't I declare my method like the following?
....
static void TestMethod1(const MyClass val)
{}
....
static void TestMethod2(const int val)
{}
....
In addition to the other good answers, I'll add yet another reason why to not put C-style constness into C#. You said:
we mark parameter as const in order to be sure that its state will not be changed in method.
If const actually did that, that would be great. Const doesn't do that. The const is a lie!
Const doesn't provide any guarantee that I can actually use. Suppose you have a method that takes a const thing. There are two code authors: the person writing the caller and the person writing the callee. The author of the callee has made the method take a const. What can the two authors assume is invariant about the object?
Nothing. The callee is free to cast away the const and mutate the object, so the caller has no guarantee that calling a method that takes a const actually will not mutate it. Similarly, the callee cannot assume that the contents of the object will not change throughout the action of the callee; the callee could call some mutating method on a non const alias of the const object, and now the so-called const object has changed.
C-style const provides no guarantee that the object will not change, and is therefore broken. Now, C already has a weak type system in which you can do a reinterpret cast of a double into an int if you really want to, so it should not be a surprise that it has a weak type system with respect to const as well. But C# was designed to have a good type system, a type system where when you say "this variable contains a string" that the variable actually contains a reference to a string (or null). We absolutely do not want to put a C-style "const" modifier into the type system because we don't want the type system to be a lie. We want the type system to be strong so that you can reason correctly about your code.
Const in C is a guideline; it basically means "you can trust me to not try to mutate this thing". That shouldn't be in the type system; the stuff in the type system should be a fact about the object that you can reason about, not a guideline to its usage.
Now, don't get me wrong; just because const in C is deeply broken doesn't mean that the whole concept is useless. What I would love to see is some actually correct and useful form of "const" annotation in C#, an annotation that both humans and compilers could use to help them understand the code, and that the runtime could use to do things like automatic paralellization and other advanced optimizations.
For example, imagine if you could "draw a box" around a hunk of code and say "I guarantee that this hunk of code performs no mutations to any field of this class" in a way that could be checked by the compiler. Or draw a box that says "this pure method mutates the internal state of the object but not in any way that is observable outside the box". Such an object could not be safely multi-threaded automatically but it could be automatically memoized. There are all kinds of interesting annotations we could put on code that would enable rich optimizations and deeper understanding. We can do way better than the weak C-style const annotation.
However, I emphasize that this is just speculation. We have no firm plans to put this sort of feature into any hypothetical future version of C#, if there even is one, which we have not announced one way or the other. It is something I would love to see, and something which the coming emphasis on multi-core computing might require, but none of this should be in any way construed to be a prediction or a guarantee of any particular feature or future direction for C#.
Now, if what you want is merely an annotation on the local variable that is a parameter that says "the value of this parameter doesn't change throughout the method", then, sure, that would be easily done. We could support "readonly" locals and parameters that would be initialized once, and a compile-time error to change in the method. The variable declared by the "using" statement is already such a local; we could add an optional annotation to all locals and parameters to make them act like "using" variables. It's never been a very high priority feature so it has never been implemented.
One of the reasons why there's no const correctness in C# is because it doesn't exist at the runtime level. Remember that C# 1.0 did not have any feature unless it was part of the runtime.
And several reasons why the CLR does not have a notion of const correctness are for example:
It complicates the runtime; besides, the JVM didn't have it either, and the CLR basically started as a project to create a JVM-like runtime, not a C++-like runtime.
If there is const correctness at the runtime level, there should be const correctness in the BCL, otherwise the feature is pretty much pointless as far as the .NET Framework is concerned.
But if the BCL requires const correctness, every language on top of the CLR should support const correctness (VB, JavaScript, Python, Ruby, F#, etc.) That's not going to happen.
Const correctness is pretty much a language feature only present in C++. So it pretty much boils down to the same argumentation as to why the CLR does not require checked exceptions (which is a Java language-only feature).
Also, I don't think you can introduce such a fundamental type system feature in a managed environment without breaking backward compatibility. So don't count on const correctness ever entering the C# world.
I believe there are two reasons C# is not const-correct.
The first is understandibility. Few C++ programmers understand const-correctness. The simple example of const int arg is cute, but I've also seen char * const * const arg - a constant pointer to constant pointers to non-constant characters. Const-correctness on pointers to functions is a whole new level of obfuscation.
The second is because class arguments are references passed by value. This means there's already two levels of constness to deal with, without an obviously clear syntax. A similar stumbling point is collections (and collections of collections, etc).
Const-correctness is an important part of the C++ type system. It could - in theory - be added to C# as something that is only checked at compile-time (it doesn't need to be added to the CLR, and wouldn't affect the BCL unless the notion of const member methods were included).
However, I believe this is unlikely: the second reason (syntax) would be quite difficult to solve, which would make the first reason (understandibility) even more of a problem.
This is possible since C# 7.2 (December 2017 with Visual Studio 2017 15.5).
For Structs and basic types only!, not for members of classes.
You must use in to send the argument as an input by reference. See:
See:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/in-parameter-modifier
For your example:
....
static void TestMethod1(in MyStruct val)
{
val = new MyStruct; // Error CS8331 Cannot assign to variable 'in MyStruct' because it is a readonly variable
val.member = 0; // Error CS8332 Cannot assign to a member of variable 'MyStruct' because it is a readonly variable
}
....
static void TestMethod2(in int val)
{
val = 0; // Error CS8331 Cannot assign to variable 'in int' because it is a readonly variable
}
....
const means "compile-time constant" in C#, not "readonly but possibly mutable by other code" as in C++. A rough analog of C++ const in C# is readonly, but that one is only applicable to fields. Aside from that, there is no C++-like notion of const correctness in C# at all.
The rationale is hard to tell for sure, because there are a lot of potential reasons, but my guess would be desire to keep the language simple first and foremost, and uncertain advantages of implementing this second.
Can anyone tell what is the point of a constant in C#?
For example, what is the advantage of doing
const int months = 12;
as opposed to
int months = 12;
I get that constants can't be changed, but then why not just... not change it's value after you initialize it?
If the compiler knows that a value is constant and will never change, it can compile the value directly into your program.
If you declare pi to be a constant, then every time it sees pi / 2 the compiler can do the computation and insert 1.57... directly into the compiled code. If you declare pi as a variable, then every time your program uses pi / 2 the computer will have to reference the pi variable and multiply it by 0.5, which is obviously slower.
I should also add that C# has readonly which is for values that the compiler cannot compute, but which cannot change for the duration of your program's execution. For example, if you wanted a constant ProgramStartTime, you would have to declare it readonly DateTime ProgramStartTime = DateTime.Now because it has to be evaluated when the program starts.
Finally, you can create a read-only property by giving it a getter but no setter, like this:
int Months { get { return 12; } } but being a property it doesn't have to have the same value every time you read it, like this:
int DaysInFebruary { get { return IsLeapYear ? 29 : 28 } }
The difference between "can't change" and "won't change" only really becomes apparent when one of the following situations obtains:
other developers begin working on your code,
third-parties begin using your code, or
a year passes and you return to that code.
Very similar questions arise when talking about data accessibility. The idea is that you want your code to provide only as much flexibility as you intend, because otherwise someone (possibly you) will come along and do something you did not intend, which leads to bugs!
If you never make mistakes, nobody on any team you work with ever makes mistakes, you never forget the exact purpose of a variable you've defined even after coming back to code you haven't looked at in months or years, and you and everyone you work with 100% reliably recognizes, understands and follows your intention of never changing a const value when you haven't bothered to use a built-in language construct that both clearly indicates and enforces constness, then no, there's no point.
If any one of those things ever turns out not to be the case, that's the point.
As for me, I find that even when I'm at my most lucid, remembering more than seven things at once is pretty close to impossible, so I'll take all the help I can get to prevent mistakes, especially when the cost is a single keyword. If you're smarter than me, and you never have to work on a team with someone less smart than you, then do whatever you want.
In some cases, there may be some compiler optimizations that can be done based on constness (constant folding, for one, which collapses expressions consisting of constants at compile-time). But usually, that's not the point.
Keep in mind you may not be the only person using the value. Not only can't you change it, but nobody using your code (as a library, for example) can change it.
And marking it as constant also makes your intent clear.
That's it. The you tell the compiler it can never change, and the compiler can optimise much better knowing that it is immutable.
Using constants programmers have the advantage of Readability over actual Value like
const double PI = 3.14159;
It also speeds up computation compared to variables by inserting values at compile time and not being inferred from a register/memory location.
For several reasons:
You want to differentiate certain values that have certain meaning from other variables.
You may later forget you are not meant to change a value, and cause unforeseen behavior.
Your code may be used by other people an they may change it (especially if you're developing a library or an API).
Because every thing that can go wrong usually will - so prevent it by making such errors discoverable at compile time rather than runtime.
Declaring a value 'const' brings the compiler into play to help you enforce personal discipline, by not allowing any changes to that value.
Also, it will catch unexpected errors due to side-effects of passing a value (that you intend to treat as a constant) into a method that takes a 'ref' parameter and could conceivably alter the value unexpectedly.
Strictly speaking, "const" isn't necessary. Python, for example, has neither "const" nor "private"; you specify your intent with the naming convention of THIS_IS_A_CONSTANT and _this_is_private.
C#, however, has a design philosophy of catching errors at compile time rather than runtime.
All about readability, different semantics for programmer is true and you should know all of it.
But constants in C# (rather in .net) has very different semantics (in terms of implementation) as compared with ordinary variables.
Because a constant value never changes, constants are always considered to be part of the
defining type. In other words, constants are always considered to be static members, not
instance members. Defining a constant causes the creation of metadata. When code refers to a constant symbol, compilers embed the value in the emitted Intermediate Language (IL) code.
These constraints mean that constants don’t have a good cross-assembly versioning story, so you should use them only when you know that the value of a symbol will never change.
The "point" is so that you can use a single program-wide variable and have only one spot to change it.
Imagine if you were making a video game that relied on knowing the FPS (frames per second) in 100 different code files. So pretend the FPS was 50... and you had the number "50" in all those files and functions... then you realize that you wanted to make it 60 FPS... instead of changing those 100 files, you would just change this:
const int FRAMES_PER_SECOND = 60;
and in those files / functions, you would use the FRAMES_PER_SECOND variable.
By the way, this has nothing to do with C#... constants are in tons of languages.
It is a case of being explicit of your intention.
If you intend to change value, then do not use 'const'.
If you do not intend to change value, then use 'const'.
That way both compiler and third party (or yourself if you read your code after long time) can know what you intended. If you or somebody makes a mistake of changing value, then compiler can detect it.
And anyways, to use 'const' is not mandatory. If you think, you can handle 'constancy' yourself (without wanting compiler to detect mistake), then do not use 'const' ;-).
You should define a variable as "const" when you know the value of this will remain constant through out your application. So once you define a const, it value must be determinable at compile time and this value will be saved into the assembly's metadata. Some more important points abt Const:
A const can be defined only for types your compiler treats as primary types.
Constants are always considered to be the part of defining type.
They are always considered to be Static members.
Constants value are always embedded directly into the code, so constants dont require any memory to be allocated to them at run time.
Because of this embedding of the value into metadata, when somebody change the value of the const (in the assembly where the const is defined) due to versioning or some other requirement
then the user of the dll has to recompile his own assembly. And this issue can be avoided using "readonly" keyword.
One of the rule that many programmers follow is: Never hard-code any variables / except 0.
that means, instead of doing
for(int i=0; i<100; i++) {}
should do
const loopCount = 100;
....
for (int i=0; i<loopCount; i++) {}
I think using const is a good reason to replace this. And indeed, there's much more reason to this:
Optimize for compiler - memory, performance.
Tell the programmer that follow your work, this is CONSTANT
If you need to refactor, change your mind in the number, you know where to go. And make sure no other places in the code would change this.
Ada, Pascal and many other languages support ranges, a way to subtype integers.
A range is a signed integer value which ranges from a value (first) to another (last).
It's easy to implement a class that does the same in OOP but I think that supporting the feature natively could let the compiler to do additional static checks.
I know that it's impossible to verify statically that a variabile defined in a range is not going to "overflow" runtime, i.e. due to bad input, but I think that something could be done.
I think about the Design by Contract approach (Eiffel) and the Spec# ( C# Contracts ), that give a more general solution.
Is there a simpler solution that checks, at least, static out-of-bound assignment at compile time in C++, C# and Java? Some kind of static-assert?
edit: I understand that "ranges" can be used for different purpose:
iterators
enumerators
integer subtype
I would focus on the latter, because the formers are easily mappable on C* language .
I think about a closed set of values, something like the music volume, i.e. a range that goes from 1 up to 100. I would like to increment or decrement it by a value. I would like to have a compile error in case of static overflow, something like:
volume=rangeInt(0,100);
volume=101; // compile error!
volume=getIntFromInput(); // possible runtime exception
Thanks.
Subrange types are not actually very useful in practice. We do not often allocate fixed length arrays, and there is also no reason for fixed sized integers. Usually where we do see fixed sized arrays they are acting as an enumeration, and we have a better (although "heavier") solution to that.
Subrange types also complicate the type system. It would be much more useful to bring in constraints between variables than to fixed constants.
(Obligatory mention that integers should be arbitrary size in any sensible language.)
Ranges are most useful when you can do something over that range, concisely. That means closures. For Java and C++ at least, a range type would be annoying compared to an iterator because you'd need to define an inner class to define what you're going to do over that range.
Java has had an assert keyword since version 1.4. If you're doing programming by contract, you're free to use those to check proper assignment. And any mutable attribute inside an object that should fall within a certain range should be checked prior to being set. You can also throw an IllegalArgumentException.
Why no range type? My guess is that the original designers didn't see one in C++ and didn't consider it as important as the other features they were trying to get right.
For C++, a lib for constrained values variables is currently being implemented and will be proposed in the boost libraries : http://student.agh.edu.pl/~kawulak/constrained_value/index.html
Pascal (and also Delphi) uses a subrange type but it is limited to ordinal types (integer, char and even boolean).
It is primarilly an integer with extra type checking. You can fake that in an other language using a class. This gives the advantage that you can apply more complex ranges.
I would add to Tom Hawtin response (to which I agree) that, for C++, the existence of ranges would not imply they would be checked - if you want to be consistent to the general language behavior - as array accesses, for instance, are also not range-checked anyway.
For C# and Java, I believe the decision was based on performance - to check ranges would impose a burden and complicate the compiler.
Notice that ranges are mainly useful during the debugging phase - a range violation should never occur in production code (theoretically). So range checks are better to be implemented not inside the language itself, but in pre- and post- conditions, which can (should) be stripped out when producing the release build.
This is an old question, but just wanted to update it. Java doesn't have ranges per-se, but if you really want the function you can use Commons Lang which has a number of range classes including IntRange:
IntRange ir = new IntRange(1, 10);
Bizarrely, this doesn't exist in Commons Math. I kind of agree with the accepted answer in part, but I don't believe ranges are useless, particularly in test cases.
C++ allows you to implement such types through templates, and I think there are a few libraries available doing this already. However, I think in most cases, the benefit is too small to justify the added complexity and compilation speed penalty.
As for static assert, it already exists.
Boost has a BOOST_STATIC_ASSERT, and on Windows, I think Microsoft's ATL library defines a similar one.
boost::type_traits and boost::mpl are probably your best friends in implementing something like this.
The flexibility to roll your own is better than having it built into the language. What if you want saturating arithmetic for example, instead of throwing an exception for out of range values? I.e.
MyRange<0,100> volume = 99;
volume += 10; // results in volume==100
In C# you can do this:
foreach(int i in System.Linq.Enumerable.Range(0, 10))
{
// Do something
}
JSR-305 provides some support for ranges but I don't know when if ever this will be part of Java.
In C#, int and Int32 are the same thing, but I've read a number of times that int is preferred over Int32 with no reason given. Is there a reason, and should I care?
The two are indeed synonymous; int will be a little more familiar looking, Int32 makes the 32-bitness more explicit to those reading your code. I would be inclined to use int where I just need 'an integer', Int32 where the size is important (cryptographic code, structures) so future maintainers will know it's safe to enlarge an int if appropriate, but should take care changing Int32s in the same way.
The resulting code will be identical: the difference is purely one of readability or code appearance.
ECMA-334:2006 C# Language Specification (p18):
Each of the predefined types is shorthand for a system-provided type. For example, the keyword int refers to the struct System.Int32. As a matter of style, use of the keyword is favoured over use of the complete system type name.
They both declare 32 bit integers, and as other posters stated, which one you use is mostly a matter of syntactic style. However they don't always behave the same way. For instance, the C# compiler won't allow this:
public enum MyEnum : Int32
{
member1 = 0
}
but it will allow this:
public enum MyEnum : int
{
member1 = 0
}
Go figure.
I always use the system types - e.g., Int32 instead of int. I adopted this practice after reading Applied .NET Framework Programming - author Jeffrey Richter makes a good case for using the full type names. Here are the two points that stuck with me:
Type names can vary between .NET languages. For example, in C#, long maps to System.Int64 while in C++ with managed extensions, long maps to Int32. Since languages can be mixed-and-matched while using .NET, you can be sure that using the explicit class name will always be clearer, no matter the reader's preferred language.
Many framework methods have type names as part of their method names:
BinaryReader br = new BinaryReader( /* ... */ );
float val = br.ReadSingle(); // OK, but it looks a little odd...
Single val = br.ReadSingle(); // OK, and is easier to read
int is a C# keyword and is unambiguous.
Most of the time it doesn't matter but two things that go against Int32:
You need to have a "using System;" statement. using "int" requires no using statement.
It is possible to define your own class called Int32 (which would be silly and confusing). int always means int.
As already stated, int = Int32. To be safe, be sure to always use int.MinValue/int.MaxValue when implementing anything that cares about the data type boundaries. Suppose .NET decided that int would now be Int64, your code would be less dependent on the bounds.
Byte size for types is not too interesting when you only have to deal with a single language (and for code which you don't have to remind yourself about math overflows). The part that becomes interesting is when you bridge between one language to another, C# to COM object, etc., or you're doing some bit-shifting or masking and you need to remind yourself (and your code-review co-wokers) of the size of the data.
In practice, I usually use Int32 just to remind myself what size they are because I do write managed C++ (to bridge to C# for example) as well as unmanaged/native C++.
Long as you probably know, in C# is 64-bits, but in native C++, it ends up as 32-bits, or char is unicode/16-bits while in C++ it is 8-bits. But how do we know this? The answer is, because we've looked it up in the manual and it said so.
With time and experiences, you will start to be more type-conscientious when you do write codes to bridge between C# and other languages (some readers here are thinking "why would you?"), but IMHO I believe it is a better practice because I cannot remember what I've coded last week (or I don't have to specify in my API document that "this parameter is 32-bits integer").
In F# (although I've never used it), they define int, int32, and nativeint. The same question should rise, "which one do I use?". As others has mentioned, in most cases, it should not matter (should be transparent). But I for one would choose int32 and uint32 just to remove the ambiguities.
I guess it would just depend on what applications you are coding, who's using it, what coding practices you and your team follows, etc. to justify when to use Int32.
Addendum:
Incidentally, since I've answered this question few years ago, I've started using both F# and Rust. F#, it's all about type-inferences, and bridging/InterOp'ing between C# and F#, the native types matches, so no concern; I've rarely had to explicitly define types in F# (it's almost a sin if you don't use type-inferences). In Rust, they completely have removed such ambiguities and you'd have to use i32 vs u32; all in all, reducing ambiguities helps reduce bugs.
There is no difference between int and Int32, but as int is a language keyword many people prefer it stylistically (just as with string vs String).
In my experience it's been a convention thing. I'm not aware of any technical reason to use int over Int32, but it's:
Quicker to type.
More familiar to the typical C# developer.
A different color in the default visual studio syntax highlighting.
I'm especially fond of that last one. :)
I always use the aliased types (int, string, etc.) when defining a variable and use the real name when accessing a static method:
int x, y;
...
String.Format ("{0}x{1}", x, y);
It just seems ugly to see something like int.TryParse(). There's no other reason I do this other than style.
Though they are (mostly) identical (see below for the one [bug] difference), you definitely should care and you should use Int32.
The name for a 16-bit integer is Int16. For a 64 bit integer it's Int64, and for a 32-bit integer the intuitive choice is: int or Int32?
The question of the size of a variable of type Int16, Int32, or Int64 is self-referencing, but the question of the size of a variable of type int is a perfectly valid question and questions, no matter how trivial, are distracting, lead to confusion, waste time, hinder discussion, etc. (the fact this question exists proves the point).
Using Int32 promotes that the developer is conscious of their choice of type. How big is an int again? Oh yeah, 32. The likelihood that the size of the type will actually be considered is greater when the size is included in the name. Using Int32 also promotes knowledge of the other choices. When people aren't forced to at least recognize there are alternatives it become far too easy for int to become "THE integer type".
The class within the framework intended to interact with 32-bit integers is named Int32. Once again, which is: more intuitive, less confusing, lacks an (unnecessary) translation (not a translation in the system, but in the mind of the developer), etc. int lMax = Int32.MaxValue or Int32 lMax = Int32.MaxValue?
int isn't a keyword in all .NET languages.
Although there are arguments why it's not likely to ever change, int may not always be an Int32.
The drawbacks are two extra characters to type and [bug].
This won't compile
public enum MyEnum : Int32
{
AEnum = 0
}
But this will:
public enum MyEnum : int
{
AEnum = 0
}
I know that the best practice is to use int, and all MSDN code uses int. However, there's not a reason beyond standardisation and consistency as far as I know.
You shouldn't care. You should use int most of the time. It will help the porting of your program to a wider architecture in the future (currently int is an alias to System.Int32 but that could change). Only when the bit width of the variable matters (for instance: to control the layout in memory of a struct) you should use int32 and others (with the associated "using System;").
int is the C# language's shortcut for System.Int32
Whilst this does mean that Microsoft could change this mapping, a post on FogCreek's discussions stated [source]
"On the 64 bit issue -- Microsoft is indeed working on a 64-bit version of the .NET Framework but I'm pretty sure int will NOT map to 64 bit on that system.
Reasons:
1. The C# ECMA standard specifically says that int is 32 bit and long is 64 bit.
2. Microsoft introduced additional properties & methods in Framework version 1.1 that return long values instead of int values, such as Array.GetLongLength in addition to Array.GetLength.
So I think it's safe to say that all built-in C# types will keep their current mapping."
int is the same as System.Int32 and when compiled it will turn into the same thing in CIL.
We use int by convention in C# since C# wants to look like C and C++ (and Java) and that is what we use there...
BTW, I do end up using System.Int32 when declaring imports of various Windows API functions. I am not sure if this is a defined convention or not, but it reminds me that I am going to an external DLL...
Once upon a time, the int datatype was pegged to the register size of the machine targeted by the compiler. So, for example, a compiler for a 16-bit system would use a 16-bit integer.
However, we thankfully don't see much 16-bit any more, and when 64-bit started to get popular people were more concerned with making it compatible with older software and 32-bit had been around so long that for most compilers an int is just assumed to be 32 bits.
I'd recommend using Microsoft's StyleCop.
It is like FxCop, but for style-related issues. The default configuration matches Microsoft's internal style guides, but it can be customised for your project.
It can take a bit to get used to, but it definitely makes your code nicer.
You can include it in your build process to automatically check for violations.
It makes no difference in practice and in time you will adopt your own convention. I tend to use the keyword when assigning a type, and the class version when using static methods and such:
int total = Int32.Parse("1009");
int and Int32 is the same. int is an alias for Int32.
You should not care. If size is a concern I would use byte, short, int, then long. The only reason you would use an int larger than int32 is if you need a number higher than 2147483647 or lower than -2147483648.
Other than that I wouldn't care, there are plenty of other items to be concerned with.
int is an alias for System.Int32, as defined in this table:
Built-In Types Table (C# Reference)
I use int in the event that Microsoft changes the default implementation for an integer to some new fangled version (let's call it Int32b).
Microsoft can then change the int alias to Int32b, and I don't have to change any of my code to take advantage of their new (and hopefully improved) integer implementation.
The same goes for any of the type keywords.
You should not care in most programming languages, unless you need to write very specific mathematical functions, or code optimized for one specific architecture... Just make sure the size of the type is enough for you (use something bigger than an Int if you know you'll need more than 32-bits for example)
It doesn't matter. int is the language keyword and Int32 its actual system type.
See also my answer here to a related question.
Use of Int or Int32 are the same Int is just sugar to simplify the code for the reader.
Use the Nullable variant Int? or Int32? when you work with databases on fields containing null. That will save you from a lot of runtime issues.
Some compilers have different sizes for int on different platforms (not C# specific)
Some coding standards (MISRA C) requires that all types used are size specified (i.e. Int32 and not int).
It is also good to specify prefixes for different type variables (e.g. b for 8 bit byte, w for 16 bit word, and l for 32 bit long word => Int32 lMyVariable)
You should care because it makes your code more portable and more maintainable.
Portable may not be applicable to C# if you are always going to use C# and the C# specification will never change in this regard.
Maintainable ihmo will always be applicable, because the person maintaining your code may not be aware of this particular C# specification, and miss a bug were the int occasionaly becomes more than 2147483647.
In a simple for-loop that counts for example the months of the year, you won't care, but when you use the variable in a context where it could possibly owerflow, you should care.
You should also care if you are going to do bit-wise operations on it.
Using the Int32 type requires a namespace reference to System, or fully qualifying (System.Int32). I tend toward int, because it doesn't require a namespace import, therefore reducing the chance of namespace collision in some cases. When compiled to IL, there is no difference between the two.
According to the Immediate Window in Visual Studio 2012 Int32 is int, Int64 is long. Here is the output:
sizeof(int)
4
sizeof(Int32)
4
sizeof(Int64)
8
Int32
int
base {System.ValueType}: System.ValueType
MaxValue: 2147483647
MinValue: -2147483648
Int64
long
base {System.ValueType}: System.ValueType
MaxValue: 9223372036854775807
MinValue: -9223372036854775808
int
int
base {System.ValueType}: System.ValueType
MaxValue: 2147483647
MinValue: -2147483648
Also consider Int16. If you need to store an Integer in memory in your application and you are concerned about the amount of memory used, then you could go with Int16 since it uses less memeory and has a smaller min/max range than Int32 (which is what int is.)
It's 2021 and I've read all answers. Most says it's basically the same (it's an alias), or, it depends on "what you like", or "by convention use int..." No answer gives you a clear when, where and why use Int32 over int. That's why I'm here.
98% of the time, you can get away with int, and that's perfectly fine. What are the other 2% ?
IO with records (struct, native types, organization and compression). Someone said an useless application is one that can read and manipulate data, but not actually capable of writing new datas to a defined storage. But in order to not reinvent the wheel, at some point, those dealing with old datas has to retrieve the documentation on how to read them. And chances are they were compiled from an era where a long was always a 32-bits integer.
It happenned before, where some had trouble remembering a db is a byte, a dw is a word, a dd is a double word, but how many bits was that about ? And that will likely happen again on C# 43.0 on a 256-bits platform... where the (future) boys never heard of "by convention, use int instead of Int32". That's the 2% where Int32 matters over int. MSDN saying today it's recommended to use int is irrelevant, it usually works with current C# version, but that may get dropped in future MSDN pages, in 2028, or 2034 ? Fewer and fewer people have WORD and DWORD encouters today, yet, two decades ago, they were common. The same thing will happen to int, in the very case of dealing with precise-fixed-length data.
In memory, a ushort (UInt16) can be a Decimal as long as it's fractional part is null, it is positive or null, and does not exceed 65535. But inside a file, it must be a short, 16-bits long. And when you read a documentation about a file structure from another era (inside the source code), you realize there are 3545 records definitions, some nested inside others, each record having between a couple and hundreds of fields of varying types.
Somewhere in 2028 a boy thought he could just get away by Ctrl-H-ing int to Int32, whole word only and match case... ~67000 changes in whole solution. Hit Run and still get CTDs. Clap clap clap. Go figure which int you should have changed to Int32 and which ones you should have changed to var. Also worth to point out Pointers are useful, when you deal with terabytes of datas (have a virtual representation of an entire planet on some cloud, download on demand, and render to user screen). Pointers are really fast in the ~1% of cases where there are so many datas to compute in realtime, you must trade with unsafe code. Again, it's to come up with an actually useful application, instead of being fancy and waste time porting to managed. So, be carefull, IntPtr is 32-bits or 64-bits already ? Could you get away with your code without caring how many bytes you read/skip ? Or just go (Int32*) int32Ptr = (Int32*) int64Ptr;...
An even more factual example is a file containing data processing and their respective commands (methods in the source code), like internal branching (a conditional continue or jump to if the test fails) :
IfTest record in file says : if value equals someConstant, jump to address. Where address is a 16-bits integer representing a relative pointer inside the file (you can go back towards the start of the file up to 32768 bytes, or up to 32767 bytes further down). But 10 years later, platforms can handle larger files and larger datas, and now you have 32-bits relative address. Your method in the source code were named IfTestMethod(...), now how would you name the new one ? IfTestMethodInt() or IfTestMethod32() ? Would you also rename the old method IfTestMethodShort() or IfTestMethod16() ? Then a decade later, you get a new command with long (Int64) relative address... What about a 128 bits command some 10 years later ? Be consistent ! Principles are great, but sometimes logic is better.
The problem is not me or you writing a code today, and it appears okay to us. It is being in the place of the one guy trying to understand what we wrote, 10 or 20 years later, how much it costs in time (= money) to come up with a working updated code ? Being explicit or writing redundant comments will actually save time. Which one you prefer ? Int32 val; or var val; // 32-bits.
Also, working with foreign data from other platforms or compile directives is a concept (today involves Interop, COM, PInvoke...) And that's a concept we cannot get rid of, whatever the era, because it takes time to update (reformat) datas (via serialization for ex.) Upgrading DLLs to managed code also takes time. We took time to leave assembler behind and go full-C. We are taking time to move from 32-bits datas to 64-bits, yet, we still need to care about 8 and 16-bits. What next in the future ? Move from 128-bits to 256 or directly to 1024 ? Do not assume a keyword explicit to you will remain explicit for the guys reading your documentation 20 years later (and documentation usually contains errors, mainly because of copy/paste).
So here it is : Where to use Int32 today over int ?
It's when you are producing code that is data-size sensible (IO, network, cross-platform data...), and at some point in the future - could be decades later - someone will have to understand and port your code. The key reason is era-based. 1000 lines of code, it's okay to use int, 100000 lines, it's not anymore. That's a rare duty only a few will have to do, and hell yeah, they have struggle, if only some were a little more explicit instead of relying on "by convention" or "it looks pretty in the IDE, Int32 is so ugly" or "they are the same, don't bother, it's a waste of time to write that two numbers and holding shift key", or "int is unambiguous", or "those who don't like int are just VB fanboys - go learn C# you noob" (yeah, that's the underlying meaning of a few comments right here)
Do not take what I wrote as a generalized perception, nor an attempt to promote Int32 on all cases. I clearly stated the specific case (as it seems to me this was not clear from other answers), to advocate for the few ones getting blammed by their supervisors for being fancy writing Int32, and at the same time the very same supervisor not understanding what takes so long to rewrite that C DLL to C#. It's an edge case, but at least for those reading, "Int32" has at least one purpose in its life.
The point can be further discussed by turning the question the other way around : Why not just get rid of Int32, Int64 and all the other variants in future C# specifications ? What that would imply ?