If I try this type definition in Visual Studio Express 2013, I get an error:
type Foo(bar : int) =
struct
member x.bar = bar
end
If I change it so that it is a class instead, I don't get any errors:
type Foo(bar : int) =
class
member x.bar = bar
end
The error I get is:
The member 'bar' can not be defined because the name 'bar' clashes with the field 'bar' in this type or module"
The error goes away if I change the constructor parameter's name slightly. I understand the differences between CLR structs and classes in general, but I don't quite understand the reason for this difference in behaviour. Can anyone explain it?
I'm mostly asking in case the answer dispels some deeper misunderstanding that I have about F#. Thanks.
Although I can't find a pertinent reference in the spec offhand, a little experimentation with a decompiler shows that primary constructor parameters on structs are always compiled as fields with the same name. For classes, a more complex set of rules (see §8.6.1.3) is used to determine their compiled form, which includes munging field names when they would otherwise clash with members.
Compare the compiled forms of this struct and class:
type S(bar: int) = struct end
type C(bar: int) =
member x.bar = bar
public class C
{
internal int bar@12;
public int bar
{
get
{
return this.bar@12;
}
}
public C(int bar)
{
this.bar@12 = bar;
}
}
public struct S : IEquatable<Program.S>, IStructuralEquatable, IComparable<Program.S>, IComparable, IStructuralComparable
{
internal int bar;
public S(int bar)
{
this.bar = bar;
}
}
The struct's primary constructor parameter is compiled as a field (and assigned!) even though it's unused. The class, on the other hand, allows a member and parameter with the same name. Admittedly, this doesn't explain why, but may help to clarify the observed behavior.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With