10
public struct MyStruct {
    static MyStruct? myProperty;
}

Trying to compile this will give me the error :
Struct member 'myStruct.myProperty' causes a cycle in the struct layout.

From what I gathered, this error usually happens when an instance of a struct contains its own struct as a property (which makes sense to me).
But here, it's about a static property, so I don't see how such a recursion could happen. Plus, the error only happens when declaring a Nullable struct, declaring a static non-nullable is safe.

What exactly is happeneing here that would cause a cycle ?


EDIT:
I did find the question I am supposedly a duplicate of; it explains why recursion happens when an Instance has a member of its own type, but this here is about static members. I know from experience that struct can have static member of their own type that won't break at runtime, this specific code only seems to break because the static member is Nullable.

Secondly, multiple people told me right away that the code compile for them; déjà-vu, the "version" of c# I am working with is for Unity, so I assume this is yet another bug with their compiler, I'll adress this question to them.
@Evk pointed out this is actually a common issue: https://github.com/dotnet/roslyn/issues/10126

Estecka
  • 388
  • 1
  • 15
  • 1
    That code compiles fine for me, so I suspect it's a version-specific bug that's either already been patched, or is a result of a new change, depending on whether your version is older or newer than mine. Either way, this is an issue for MS support, not SO. – Servy Nov 22 '17 at 20:15
  • What version of C# are you using? The cycle detector used to have a number of interesting bugs in it, and that was one of the simpler ones. The more complex topologies that triggered the cycle detecter were quite weird. For example, the cycle detector used to mark `class N {} class R : N { public class S { public class T{} } }` as a cycle, even though obviously it is not. – Eric Lippert Nov 22 '17 at 20:16
  • Possible duplicate of [Cycle in the struct layout that doesn't exist](https://stackoverflow.com/questions/9296251/cycle-in-the-struct-layout-that-doesnt-exist) – Reyan Chougle Nov 22 '17 at 20:21
  • 2
    @ReyanChougle The proposed duplicate isn't using a static field. This is. The two are completely different. – Servy Nov 22 '17 at 20:22
  • I doubt this is a duplicate: The other questions is about an instance member while I declared a Static member. Others say the code compiled for them, so I'll just assume this is a bug in Unity's compiler, would only be the second I found this week. – Estecka Nov 22 '17 at 20:27
  • @Evk No, it is not in fact going to error any time you have a type with a static member of its own type (otherwise basically every Singleton implementation would break). If the type initializer calls something that uses the type being initialized it doesn't throw, it just uses the static members without them having been initialized (they're all at their default values). – Servy Nov 22 '17 at 20:27
  • @Servy but I mean accessing this concrete struct mentioned in question will throw `TypeLoadException` at runtime. Though now I'm not sure I understand why, because it happens only if `myProperty` is `Nullable`, not happens if it's just `MyStruct`. – Evk Nov 22 '17 at 20:28
  • 1
    @Servy I found this https://github.com/dotnet/roslyn/issues/10126 but still without much explanation of the reasons why it fails. – Evk Nov 22 '17 at 20:34
  • 2
    That happens with any `SomeGenericStruct` field, not just `Nullable`, and not relevant whether field is static or not, so some bug in CLR with such types. Anyway, @Estecka, no need to complain about this wrong warning, because your code would otherwise have failed at runtime anyway :) – Evk Nov 22 '17 at 20:46
  • My you're right, I didn't catch this actually had to do Generic types. Thank for the link, that was at least instructive. – Estecka Nov 22 '17 at 21:25
  • @Evk: the thread on the github issue is extremely confusing because some people contributing to the thread got off on a wrong tangent early on and took some convincing that they were heading off into the weeds. The issue described there is an issue in the CLR type loader itself, and not in the C# compiler proper. The C# compiler proper has also had a number of defects where it improperly detected a cycle when there wasn't one, and some of those might have been shielding users from activating similar underlying CLR bugs. – Eric Lippert Nov 22 '17 at 21:47
  • @EricLippert yes after some reading of that thread I found your reply somewhere in the middle explaining that. – Evk Nov 22 '17 at 21:50
  • See also https://stackoverflow.com/questions/36222117/maybe-a-c-sharp-compiler-bug-in-visual-studio-2015 which is what inspired the github issue in the first place. But again, this issue is a CLR defect, not an error in the C# compiler cycle detector. The issue reported by the original poster is different. – Eric Lippert Nov 22 '17 at 21:53

1 Answers1

1

While looking for a workaround I found two things:

One, properties with accessors work fine, so where a Readonly is needed you can just do this :

public struct myStruct {
    public static myStruct? myProperty { get{ /*...*/ } } 
}

Second, you can still store a field somewhere within the struct as long as it's nested :

public struct myStruct {
    public static class nest {
        public static Nullable<myStruct> myNestedProperty;
    }
}

The latter is kinda ugly, (and fortunately I didn't need a setter), but at least that's a working workaround.

Estecka
  • 388
  • 1
  • 15