Skip to content

Record update syntax not allowed for same type in [<Struct>] record member #8670

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

Closed
nikonthethird opened this issue Mar 6, 2020 · 5 comments

Comments

@nikonthethird
Copy link

The F# compiles shows error FS3232 when attempting to construct a new struct record of the same type in a member of the record with the update syntax.

Repro steps

[<Struct>]
type R = {
    X : int32
    Y : string
} with
    member this.Shift n = { this with X = this.X <<< n }
    //                      ^^^^ Struct members cannot return the address of fields of the struct by reference

Expected behavior

The update should be allowed, since it's constructing an immutable copy.

Actual behavior

The compiler shows error FS3232: Struct members cannot return the address of fields of the struct by reference

Known workarounds

Naming all fields explicitly works:

[<Struct>]
type R = {
    X : int32
    Y : string
} with
    member this.Shift n = { X = this.X <<< n; Y = this.Y }

Related information

  • Windows 10, Ubuntu 18.04
  • .NET Framework 4.7.2, F# runtime 4.7.0.0
  • Visual Studio 2019
@abelbraaksma
Copy link
Contributor

I may be wrong, but I think I've seen in some other discussion that this is a "by design" thing, because this is implicitly a byref. Though there's something to say for the record update syntax to work with byrefs, since indeed it'll create a copy anyway (unless the record update syntax with byrefs actually updates in place? If so, the error is genuine)

@TheJayMann
Copy link
Contributor

I just tried, as a workaround, you can do the following.

[<Struct>]
type R = {
  X : int32
  Y : string
} with
  member self.Shift n = let this = self in { this with  X = this.X <<< n}

I tested that it works, though I do not know how, if at all, it would affect the performance.

@cartermp
Copy link
Contributor

cartermp commented Mar 6, 2020

Closing as dupe of #7536

@cartermp cartermp closed this as completed Mar 6, 2020
@abelbraaksma
Copy link
Contributor

abelbraaksma commented Mar 6, 2020

I tested that it works, though I do not know how, if at all, it would affect the performance.

@TheJayMann What you're doing is making a shallow copy of the reference, and this action dereferences the inref (see linked issue for more info).

I think that one possible solution to this bug could be exactly like the code you showed.

@abelbraaksma
Copy link
Contributor

abelbraaksma commented Mar 6, 2020

Another, more idiomatic solution for the scenario of the OP is to create a static member, or a let function. The same syntax (from OP) can then be used without worrying about inref, and it simply makes more sense: after all, you're not doing any action on the type, or changing it's state, a static method is than the more obvious choice ;).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants