Skip to content

[Proposal]: Avoid synthesizing parameterless struct constructors #5552

@cston

Description

@cston

Avoid synthesizing parameterless struct constructors

  • Proposed
  • Prototype: Not Started
  • Implementation: Not Started
  • Specification: Not Started

Summary

Avoid synthesizing a parameterless constructor for struct types; run field initializers from declared constructors only;
and report an error if the struct declaration includes field initializers but no constructors.

Motivation

With C#10, if a struct type declaration includes field initializers but no constructors, the compiler will synthesize a parameterless constructor that will run the field initializers.

The compiler does not synthesize a parameterless constructor if there are explicit constructors because,
with record struct types, the field initializers are bound in the context of the primary constructor so the synthesized parameterless constructor would need to invoke the primary constructor to run the field initializers. But what values should be passed for the primary constructor arguments?

The fact that a parameterless constructor is synthesized in some cases but not all makes it difficult to understand when new() is equivalent to default, and it means the result of new() can change silently when non-default constructors are added or removed.

// With no constructors
struct S
{
    public int Value = 42;
}

WriteLine(new S().Value); // 42
// After adding non-default constructor
struct S
{
    public int Value = 42;
    public S(string message) { }
}

WriteLine(new S().Value); // 0

If instead, struct constructors are never synthesized, then the behavior is simplified:

  • Parameterless constructors can be declared explicitly.
  • Field initializers are run from declared constructors only.
  • Unless the struct type declares a parameterless constructor, new() is equivalent to default, consistent with C#9 and before.

Detailed design

Never synthesize a parameterless constructor for struct types.

Report an error if a struct type declaration includes field initializers but no explicit constructors.

// With no constructors
struct S
{
    public int Value = 42; // error: containing type 'S' has no declared constructor
}

WriteLine(new S().Value); // error above
// After adding parameterless constructor
struct S
{
    public int Value = 42;
    public S() { }
}

WriteLine(new S().Value); // 42
// After adding non-default constructor instead
struct S
{
    public int Value = 42;
    public S(string message) { }
}

WriteLine(new S().Value); // 0

Drawbacks

It is a breaking change from C#10 to require an explicit constructor if there are field initializers, but it's not a silent break (an error is reported), and the fix is simple (add an empty parameterless constructor).

Alternatives

Unresolved questions

Design meetings

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions