1
int x = 6;

it works, but

Int32 x = new Int32(6);

does not. Why Int32's default constructor parameterless? how does it assigns 6 to x?

edit: more explanation.. https://referencesource.microsoft.com/#mscorlib/system/int32.cs,225942ed7b7a3252 line 38:

internal int m_value;

how compiler does assign 6 to this m_value? Int32's constructor is parameterless.

  • 1
    Its done by compiler. So that is underhood magic, thats all – Evgeny Gorbovoy Mar 21 '18 at 14:40
  • `Int32 x = new Int32(6);` is not the same as `int x = 6;`. The same would be `Int32 x = 6;`, what works for sure, since `int` is just the alias for `Int32`. – L. Guthardt Mar 21 '18 at 14:43
  • `Int32` is a convenience type to give integers a representation in the object model, but it is not what the language and runtime "really" use when working with ints, since they have native support for that. `int x = 6` gets translated to `ldc.i4.6`, directly producing an integer constant without involving the struct type at all. – Jeroen Mostert Mar 21 '18 at 14:44
  • Int32 x = 6? Its work – Alvarez Mar 21 '18 at 14:44
  • 1
    I think `System.Int32` does not even have a parameterless constructor. – Tim Schmelter Mar 21 '18 at 14:44
  • 2
    @TimSchmelter - All structs have a default constructor. – Lee Mar 21 '18 at 14:45
  • 1
    @TimSchmelter *all* structs have a parameterless constructor. Of course you can just compile the code to see for yourself, rather than believing strangers on the internet. – Servy Mar 21 '18 at 14:45
  • @Servy: J.Skeet isn't a stranger: https://stackoverflow.com/questions/333829/why-cant-i-define-a-default-constructor-for-a-struct-in-net/333840#333840 – Tim Schmelter Mar 21 '18 at 14:45
  • 1
    @TimSchmelter You can't define your own *custom* parameterless constructor for any struct. It *must* exist, but it's behavior cannot be changed. It can only ever have the default behavior. The fact that you can't create a *custom* parameterless constructor, or change its behavior, doesn't mean it doesn't exist. – Servy Mar 21 '18 at 14:47
  • Side note: In the .Net framework, a **default constructor** is parameter-less by definition. – Zohar Peled Mar 21 '18 at 14:49
  • @Servy: here's another stranger from internet who says that there is no default constructor in `System.Int32`: https://stackoverflow.com/questions/25839595/why-cant-we-find-int32s-default-constructor-using-getconstructor – Tim Schmelter Mar 21 '18 at 14:49
  • 1
    Whether or not `Int32` should be considered to have a default constructor is mostly a point of view. If you ask C#, then yes it does, since you can write `new Int32()`. If you ask the runtime, then no, since `Int32` has no constructors at all. No constructor is ever invoked, which makes sense, since `Int32` instances are not *really* involved when working with ints. – Jeroen Mostert Mar 21 '18 at 14:50
  • @TimSchmelter That's someone saying that there is no information about it in reflection. It exists, and can be used, there just isn't meta information about it. Again, if you want to see if it has a parameterless construct just go ahead and try to compile `new Int32();` and see if it tells you that no such constructor exists, it's a simple test to perform. – Servy Mar 21 '18 at 14:51
  • 4
    @Servy: that could be compiler magic that lets you believe there is one when there is actually none – Tim Schmelter Mar 21 '18 at 14:52
  • @TimSchmelter You can look at the documentation to see that it explicitly says that all structs have a default constructor, if you really care about what it's called to see that it *is* in fact a constructor, I guess, and that it's not some other type of operation that just appears to be a constructor (like, say, when writing `new Action(someMethod);`, which isn't actually a constructor). – Servy Mar 21 '18 at 15:04
  • Note that `newobj instance void [mscorlib]System.Int32::.ctor()` is not legal -- you can assemble it, but you'll get a `MissingMethodException` at runtime. Of course, this is not code that actually gets emitted by anything, since that's not how you produce `int`s. Again: from a C# point of view, there is a default constructor, since all structs have a default constructor; from an IL point of view, there is not, and no type is required to have a constructor. Both points of view are equally legit, as long as they're clearly identified. – Jeroen Mostert Mar 21 '18 at 15:08
  • "how compiler does assign 6 to this m_value" -- it doesn't. When the runtime is asked to treat an `int` as an instance of `Int32`, it will make sure that `m_value` reflects the value of the integer. Neither the compiler nor the runtime are constrained by the rules of C#, like programmers are. For efficiency reasons, the runtime has special handling for types like `Int32`. You will not even see any explicit reference to `m_value` in bytecode -- when this source is compiled, the compiler knows to translate it to integer instructions (using `ldind.i4` rather than `ldfld`). – Jeroen Mostert Mar 21 '18 at 15:26
  • The declaration for Int32 that you can find in the framework source is pretty misleading. They dotted the i's and crossed the t's, but the compiler and jitter know far too much about Int32 to ever let that code run. It does matter, somewhat, that m_value is used by BinaryFormatter and the struct declaration is compatible with the layout of a boxed Int32. But that constructor won't, this is caught early by the C# compiler and it emits the dedicated CIL opcode to initialize an int. – Hans Passant Mar 21 '18 at 15:35

2 Answers2

3

How does it assign 6 to x?

6, the literal, is already an integer. The language is designed in a way that there are literal expressions within the syntax which are directly interpreted by the the compiler.

A plain 6 is an integer literal and already corresponds to an Int32 object with the value 6. The compiler does not actually need to call a constructor for literals but can create the objects directly. Depending on the type, there may be different syntaxes for different literals. For example a string literal "foo" also makes the compiler create a string object with the value “foo” directly.

Note that this is nothing special to C# and its typing system. So whether Int32 is a value type or not does not actually matter (String is not even a value type and there are still literals).

poke
  • 369,085
  • 72
  • 557
  • 602
  • May be one interesting fact can be added: "already corresponds to an Int32 object with the value 6" is not completely true. There is no any "object" or structure in memory at that moment. There is exactly 4 bytes inside method frame to which 4 bytes (with value 6) will be copied from process memory. – Evgeny Gorbovoy Aug 27 '19 at 13:44
2
x = 6;

After compilation becomes:

IL_0001: ldc.i4.6     
IL_0002: stloc.0      

So as you see .NET has instruction for creation integer values from literals. It's done under the hood.

ldc.i4.6 creates "6" and put it onto the top of the stack. (that is actually creation of integer value)

stloc.0 copies value from the top of the stack in to variable x

Evgeny Gorbovoy
  • 765
  • 3
  • 20
  • thanks for il output. is it means compiler doesn't use Int32 struct when we write Int32 x = new Int32(); ? – csharp newbie Mar 21 '18 at 15:33
  • 1
    @csharpnewbie: that is compiled to `ldc.i4.0 ; stloc.0`, so no. You can verify such things yourself with LINQPad; it has an option to output the compiled IL directly. – Jeroen Mostert Mar 21 '18 at 16:16
  • @csharpnewbie compiler does not use anything from Int32 during creation, but after it is created it is exactly Int32 structure - it has methods, fields and so on – Evgeny Gorbovoy Mar 21 '18 at 16:44