Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow IsByRefLike and IsReadOnly anonymous records #712

cartermp opened this Issue Jan 15, 2019 · 0 comments


None yet
1 participant
Copy link

cartermp commented Jan 15, 2019

I propose we allow ByRefLike and ReadOnly struct anonymous records.

You can create struct anonymous records as such today:

let f (r: struct {| IntVal: int |}) = r.IntVal
f {| IntVal=12 |}
// Or if you don't like structness inference: f struct {| IntVal=12 |}

However, there is no ability to make them ByRefLike, which means you cannot have them contain other ByRefLike structs such as Span<'T>.

A possible declaration syntax might look like this:

// Attribute
let f ([<IsByRefLike>] r: {| S: Span<int> |}) = S.Length

// Keyword
let a (r: byref struct {| S: Span<int> |}) = S.Length
let b (r: struct byref {| S: Span<int> |}) = S.Length
let c (r: byreflike {| S: Span<int> |}) = S.Length // 'byrefLike' implies struct

It would be sort of nonsense to have you require an attribute to instantiate one, so a keyword would likely be needed:

a byref struct {| S = Span<int>.Empty |}
b struct byref {| S = Span<int>.Empty |}
c byreflike {| S = Span<int>.Empty |} // 'byrefLike' implies struct

Or perhaps structness inference would take care of the instantiation site:

// Inferred to by a ByRefLike struct anonymous record
a {| S = Span<int>.Empty |}

Similarly, there is no way to define a IsReadOnly struct anonymous record. Possible declaration syntax:

// Attribute
let f ([<IsReadOnly>] r: {| F: FooReadOnly<int> |}) = S.Length

// Keyword
let a (r: readonly struct {| F: FooReadOnly<int> |}) = S.Length
let b (r: struct readonly {| F: FooReadOnly<int> |}) = S.Length
let c (r: readonly {| F: FooReadOnly<int> |}) = S.Length // 'readonly' implies struct

And an instantiation syntax:

a readonly struct {| F = FooReadOnly<int>.Empty |}
b struct readonly {| F = FooReadOnly<int>.Empty |}
c readonly {| F = FooReadOnly<int>.Empty |} // 'byrefLike' implies struct

Declaration syntax options for having both:

// Attribute declaration
let f ([<IsReadOnly; IsByRefLike>] r: {| S: ReadOnlySpan<int> |}) = S.Length

// Syntax declarations
let a (r: byreflike readonly struct {| S: ReadOnlySpan<int> |}) = S.Length
let b (r: struct byreflike readonly {| S: ReadOnlySpan<int> |}) = S.Length
let c (r: byreflike readonly {| S: ReadOnlySpan<int> |}) = S.Length // 'byrefLike' and 'readonly' imply struct

Instantiation syntax for having both:

a byref readonly struct {| R = ReadOnlySpan<int>.Empty |}
b struct byref readonly {| R = ReadOnlySpan<int>.Empty |}
c byreflike readonly struct {| R = ReadOnlySpan<int>.Empty |}

Structness inference could capture both IsByRefLike and IsReadOnly:

f {| R = ReadOnlySpan<int>.Empty |} // Only works if the input type is byref-like and readonly

Pros and Cons


  • Parity with records
  • Allows you to use these more ephemeral constructs in the perf-sensitive environments ByRefLike structs are intended for


  • I can't think of an explicit instantiation syntax that doesn't kind of suck
  • This can make an input parameter heavy syntax-wise
  • These kinds of structs are done with attributes in F# today, but to enable them for anonymous records would require a keyword due to the lack of support for attributes on function parameters
  • Allowing a keyword instead of an attribute is inconsistent with how you define ByRefLike structs today in F#

Extra information

Estimated cost (XS, S, M, L, XL, XXL): M

Affidavit (please submit!)

Please tick this by placing a cross in the box:

  • This is not a question (e.g. like one you might ask on stackoverflow) and I have searched stackoverflow for discussions of this issue
  • I have searched both open and closed suggestions on this site and believe this is not a duplicate
  • This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it.

Please tick all that apply:

  • This is not a breaking change to the F# language design
  • I or my company would be willing to help implement and/or test this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.