Skip to content

Adding new field kind should be considered breaking change #112033

Closed

Description

@AaronRobinsonMSFT

In #111584, the alignment of ref struct types was relaxed if the type didn't contained object or byref fields. The previous behavior was that a ref struct was always pointer aligned. This change resulted in the following question:

Do we need to add this to breaking-change-rules.md? Would we consider it a breaking change to add a ref field to a ref struct that didn't previously have a ref field?

_Originally posted by @MichalStrehovsky in #111584 (review)

Initially this was accepted but then reverted due to pushback about the layout of types was an implementation details unless specifically documented.

If the libraries folks agree, I think it would be fine to explicitly match the current Roslyn behavior and say that adding first field of a new kind to an existing value type is disallowed change. Kind can be any of objref, byref or generic type argument, and the rule applies recursively.

Introducing new significant state in existing value types is close to impossible to do in compatible way for other reasons (e.g. it is why we have both DateTime and DateTimeOffset), so these situations do not come up in practice. I guess it is the reason why nobody bothered to mention it in the breaking changes doc up until now.

Originally posted by @jkotas in #111584 (comment)

The question now goes to the Libraries team, @stephentoub, and perhaps the .NET API review team, @bartonjs, to help us decide if adding a new kind of field (that is, objref, byref or generic type argument), to an existing value type should be considered a change that should result in a breaking change announcement.

Activity

  1. added this to the 10.0.0 milestone on Jan 31, 2025
  2. changed the title [-]Adding new field type should be considered breaking change[/-] [+]Adding new field kind should be considered breaking change[/+] on Jan 31, 2025
  3. stephentoub commented on Jan 31, 2025

    @stephentoub
    Member

    decide if adding a new kind of field (that is, objref, byref or generic type argument), to an existing value type should be considered a change that should result in a breaking change announcement

    Yes, anywhere adding a new field to a struct could impact how Roslyn handles that type should be breaking. There's also the issue of tearing, where adding an additional field to a one primitive/reference field struct could introduce the possibility of tearing, but we generally haven't documented that as breaking (though we also rarely do it).

  4. jkotas commented on Jan 31, 2025

    @jkotas
    Member

    adding first field of a new kind to an existing value type is disallowed change. Kind can be any of objref, byref or generic type argument, and the rule applies recursively.

    I am not sure whether this is accurate. Should objrefs and byrefs be treated as the same kind? Adding an objref field to a ref struct with a ref field should be fine. Also, adding a byref field to a ref struct with an objref field should be fine too.

  5. AaronRobinsonMSFT commented on Jan 31, 2025

    @AaronRobinsonMSFT
    MemberAuthor

    I am not sure whether this is accurate. Should objrefs and byrefs be treated as the same kind? Adding an objref field to a ref struct with a ref field should be fine. Also, adding a byref field to a ref struct with an objref field should be fine too.

    From the perspective of the newly added layout support that started this conversation, yes, they have the same impact.

    Yes, anywhere adding a new field to a struct could impact how Roslyn handles that type should be breaking.

    Roslyn isn't the issue in this specific case, although I do agree that impacting Roslyn should be a breaking change. The question that started the current conversation is only currently detected at run-time and would result in a TypeLoadException.

    Motivating example:

    ref struct FxType
    {
        public int F;
    }
    
    [StructLayout(LayoutKind.Explicit)]
    ref struct UserType
    {
        public int F1;
    
        [FieldOffset(4)] 
        public FxType F2;
    }

    In the next release of .NET, the FxType is updated to the following causing the loading of UserType to fail on a 64-bit runtime.

    ref struct FxType
    {
        public int F;
        public ref int RF; // Could also be an objref instead of byref.
    }
  6. stephentoub commented on Jan 31, 2025

    @stephentoub
    Member

    The question that started the current conversation is only currently detected at run-time and would result in a TypeLoadException.

    Then definitely yes :)

  7. added
    in-prThere is an active PR which will close this issue when it is merged
    on Feb 3, 2025
  8. locked and limited conversation to collaborators on Mar 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-Metain-prThere is an active PR which will close this issue when it is merged

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions