3
    let rect = new Rectangle(x, y, sprite.Width, sprite.Height)
    rect.X <- 888

The second line fails in F#, but in C# the assignment works. I am not sure why.

Marko Grdinić
  • 3,798
  • 3
  • 18
  • 21
  • In what way does it fail? What is the full type name of rectangle? I'm guessing not the struct from System.Drawing in the full .net framework. – DaveShaw Jan 19 '16 at 20:29
  • 1
    The interesting thing here is that the [`Rectangle`](https://github.com/mono/MonoGame/blob/develop/MonoGame.Framework/Rectangle.cs) is a struct and [probably shouldn't be muttable](https://blogs.msdn.microsoft.com/ericlippert/2008/05/14/mutating-readonly-structs/) but it is and always has been (in both MonoGame and XNA). I'd argue that F# is helping by making it clear that something is wrong here where as C# hides the problem. – craftworkgames Jan 20 '16 at 03:29

2 Answers2

9

Rectangle is a struct rather than a class. You can have that line work as you'd expect if you mark the value with mutable:

let mutable rect = new Rectangle(10, 21, 10, 21)
rect.X <- 888

This is actually quite interesting, as F# makes the value-type semantics of structs more visible compared to what C# does.

rect.X <- 888 does not really mutate the field, rather it updates rect with a new value of the struct with the X field modified. So you can imagine it does an equivalent of rect <- { rect with X = 888 }. At that point it's quite clear why the compiler wants to see mutable there.

I wonder why F# designers didn't prohibit assignment syntax for structs and go with something similar to the record syntax. Probably they didn't want to make it too different compared to C#.

scrwtp
  • 13,437
  • 2
  • 26
  • 30
3

As the compiler is probably saying,

A value must be mutable in order to mutate the contents or take the address of a value type, e.g. 'let mutable x = ...'

In F#, let creates an immutable variable (i.e. a value). The compiler enforces this by not letting you mutate it. You must write let mutable to get an equivalent variable declaration to what you had in C#.

Note that if Rectangle was a reference type, F# wouldn't complain, because you'd be modifying what is referenced by the value, not the value itself. In the case of a value type (like Mono's Rectangle), the identifier bound to the value is the value itself, so you cannot mutate it.

Asik
  • 21,506
  • 6
  • 72
  • 131