Two ways to define struct

Hi,

following on previous post, why are there two ways to define a struct?
Is there actually any difference to how the different ways implement/operate?

type t1 =
  struct
    val x : int
    val y : int
  end
  new(a,b) =
    {
      x = a
      y = b
    }
type t2 =
  {
    x: int
    y: int
  }
[<Struct>]
type t3 =
  {
    x: int
    y: int
  }

I believe that they are simply two different ways to define the same thing.
I haven’t seen any article/definition which even gives a hint that the two could be functionally different in any way, but I’ve not looked everywhere.

In the code which I have read, it seems that the attribute is more-commonly used when other attributes are used, but I don’t think that’s a rule which needs to be adhered to.

I would be happy to learn that I am wrong about this.

I think t3 is officially a “record” that happens to be a struct, while t1 is not a record, and behaves the same as a struct in C#. I think t3 is the more idiomatic one you’ll see in more community F# code. Obviously, it’s much less verbose than t1. Other differences I’m aware of include how you construct them, where t3 will be constructed with the “normal” record syntax: { x = 1; y = 3 } while t1 will use a constructor function instead t1(1, 3). t3 gets the record “copy-and-update” feature, where you can do { myT3 with x = 4 }. I think with t3 you can control equality and comparison with [<CustomEquality>], [<CustomComparison>], [<NoEquality>], [<NoComparison>], [<EqualityConditionalOn>] and friends, and I don’t think you can do the same with t1. There might be other record features that t3 has that t1 doesn’t, but I’m not aware of others.

If I were to guess, the t1 syntax exists because that was the only way to create structs prior to the [<struct>] tag being introduced in F# 4.1

I think you already know this, but t2 is a very different animal from t1 and t3, as it’s an object instead of a struct. That means its fields are heap allocated instead of stack allocated. That can either help or hurt your performance based on usage, and can be a little tricky to figure out which is better in a given situation.