Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the IL set this value twice?

I was trying around a bit with Try Roslyn when I entered this piece of code:

using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.CSharp;

public class C {

    public C()
    {
        x = 4;
    }

    public int x { get; } = 5;
}

And it gave me back this code:

using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
[assembly: AssemblyVersion("0.0.0.0")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[module: UnverifiableCode]
public class C
{
    [DebuggerBrowsable(DebuggerBrowsableState.Never), CompilerGenerated]
    private readonly int <x>k__BackingField;
    public int x
    {
        [CompilerGenerated]
        get
        {
            return this.<x>k__BackingField;
        }
    }
    public C()
    {
        this.<x>k__BackingField = 5;
        base(); // This is not valid C#, but it represents the IL correctly.

        this.<x>k__BackingField = 4;
    }
}

What I don't get is why it would do the assignment of the backing field twice inside of the constructor:

        this.<x>k__BackingField = 5;
        base(); // This is not valid C#, but it represents the IL correctly.

        this.<x>k__BackingField = 4;. 

Is this an error of the website or does the Roslyn compiler actually do this (would be really dumb imo)?


What I mean is that if I do

 public C(int x)
 {
   this.x = x;
 }

public int x { get; } = 5;

And have that code created:

public C(int x)
{
    this.<x>k__BackingField = 5;
    base(); // This is not valid C#, but it represents the IL correctly.

    this.<x>k__BackingField = x;
}

But shouldn't it optimize that out?

like image 282
Mafii Avatar asked May 25 '16 12:05

Mafii


People also ask

Why do computers mess up floating point math?

Because JavaScript uses the IEEE 754 standard for Math, it makes use of 64-bit floating numbers. This causes precision errors when doing floating point (decimal) calculations, in short, due to computers working in Base 2 while decimal is Base 10.

Why is it called floating point?

A floating point number, is a positive or negative whole number with a decimal point. For example, 5.5, 0.25, and -103.342 are all floating point numbers, while 91, and 0 are not. Floating point numbers get their name from the way the decimal point can "float" to any position necessary.

What is a floating point type?

The floating-point data type is a family of data types that act alike and differ only in the size of their domains (the allowable values). The floating-point family of data types represents number values with fractional parts. They are technically stored as two integer values: a mantissa and an exponent.

What is a value in Java?

A generic holder for the value of a property. A Value object can be used without knowing the actual property type ( STRING , DOUBLE , BINARY etc.). Any implementation of this interface must adhere to the following behavior: A Value object can be read using type-specific get methods.


2 Answers

Because you set it twice in your code:

public C()
{
    //here
    x = 4;
}

//and here
public int x { get; } = 5;

Update after edit of question

But shouldn't it optimize that out?

It probably could, but only if that class doesn't inherit from another class that uses that value in its constructor, it knows that it's an auto-property and the setter doesn't do anything else.

That would be a lot of (dangerous) assumptions. The compiler needs to check a lot of things before making an optimization like that.

like image 63
Manfred Radlwimmer Avatar answered Oct 01 '22 00:10

Manfred Radlwimmer


The reason is that you are setting it twice in your code, both in the property declaration and in the constructor.

The C# 6.0 readonly property

public int x { get; }

Works just like a readonly field regarding value assignment: you can set it in either the constructor or at the place of the declaration.

EDIT

  • There are two parts of this issue: First, the current http://tryroslyn.azurewebsites.net/ (as of 2016.05.25) compile the code in DEBUG mode, even if the Release option is chosen at the header of the page.
  • Second the Roslyn really does not optimize out the double declaration of the readonly property, so if you use VS15 and compile this code in release mode, the x will be assigned twice as well

An example for the usage of initializing the readonly property for multiple time can be the usage of multiple constructors, where only one redefines the "default" value you set for the property.

However in your case, optimization would not be a bad idea, it might be worthwhile to raise this as a feature request on the Roslyn github page

like image 35
Márk Gergely Dolinka Avatar answered Oct 01 '22 00:10

Márk Gergely Dolinka