Simplified repro from original issue:
using System;
var x = new S3Options { BasePath = "p/a/t/h", Bucket = "root" };
var y = new S3Options { BasePath = "p/a/t/h" };
Console.WriteLine(y.Bucket);
public record struct S3Options
{
public string? Bucket { get; init; }
public string? BasePath { get; init; } = "value";
}
This prints out root where it should print out nothing. The reason this is happening is that we are re-using a local for initialization purposes. This is a practice we've had since probably C# 1.0. Prior to C# 10 though we cleared out the local between uses via .initobj instruction. In C# 10 though when there is a parameterless struct ctor, explicit or implicit because of initializers, we call the .ctor on the struct instead.
IL without paramterless ctor
IL_0024: ldloca.s 2
IL_0026: initobj S3Options
IL_002c: ldloca.s 2
IL_002e: ldstr "p/a/t/h"
IL with parameterless ctor
IL_0023: ldloca.s 2
IL_0025: call instance void S3Options::.ctor()
IL_002a: ldloca.s 2
IL_002c: ldstr "p/a/t/h"
The .ctor call though does not clear out all of the existing values, it just sets the minimal necessary set. Because Bucket doesn't have an explicit initializer it ends up re-using the previous value.
Simplified repro from original issue:
This prints out
rootwhere it should print out nothing. The reason this is happening is that we are re-using a local for initialization purposes. This is a practice we've had since probably C# 1.0. Prior to C# 10 though we cleared out the local between uses via.initobjinstruction. In C# 10 though when there is a parameterlessstructctor, explicit or implicit because of initializers, we call the.ctoron thestructinstead.IL without paramterless ctor
IL with parameterless ctor
The
.ctorcall though does not clear out all of the existing values, it just sets the minimal necessary set. BecauseBucketdoesn't have an explicit initializer it ends up re-using the previous value.