I want to write the equivalent of this C# in F#:
struct Vector2 {
public readonly int X;
public readonly int Y;
public Vector2(int x, int y) {
X = x;
Y = y;
}
}
This forces the user to supply arguments to create an instance [EDIT: this is wrong for value types - all value types have a default constructor]. A default Vector2 could be provided with a static readonly field as well, i.e. Vector2.Zero.
It looks like the only way to get public fields is via the "val" keyword, but doesn't seem to let me initialize them with the default constructor, and I don't want to have two constructors:
[<Struct>]
type MyInt(value) =
val public Value : int = value;;
val public Value : int = value;;
-------------------------------^
stdin(7,32): error FS0010: Unexpected symbol '=' in member definition
I know this can be done with member bindings but this creates properties, not fields, if I understand well.
According to this http://msdn.microsoft.com/en-us/library/vstudio/dd233233.aspx, that could be done as
type Vector2 =
struct
val public X: int
val public Y: int
new(x: int, y: int) = { X = x; Y = y }
end
If an F# Record would work for you, then this will work:
type MyInt = {
Value: int
};;
Then to initialize:
let i = {Value=1};;
Since I'm not completely sure of your use case, I'm not sure how helpful this is.
EDIT:
For what it's worth, if your reason for preferring a value type is that you want value type equality semantics, records support that (even though they are reference types). Consider this:
type Vector2 = {
X:int;
Y:int
};;
type Vector2 =
{X: int;
Y: int;}
let v = {X=1;Y=1};;
val v : Vector2 = {X = 1;
Y = 1;}
let v2 = {X=1;Y=1};;
val v2 : Vector2 = {X = 1;
Y = 1;}
v = v2;;
val it : bool = true
let v3 = {X=2;Y=2};;
v = v3;;
val it: bool = false
I mean to say that even though records are reference types, one of the reasons that people use value types (the equality semantics) is not a problem with records. Even though it's a reference type, I believe it's a lot closer to the behavior of the C# code you're trying to emulate--for what it's worth.
Related
I have the type declaration
type MYVAL = INT of int
and want to perform arithmetic operations on constants and variables of type MYVAL, like
let a : MYVAL = 10
let b : MYVAL = 25
let c = a+b
However, when I run it, it claims that MYVAL does not support the operator +. Isn't MYVAL treated as an integer type? If it is not, what does INT of int do? How would you perform arithmetic operations of variables and constants of type MYVAL?
MYVAL is not treated as an integer type. If that's what you want, you can use a type abbreviation; type MYVAL = int. I'm not sure why you would want to do that, but it's definitely possible.
In your current definition, MYVAL is a single case discriminated union. It wraps a given type, but doesn't inherit any of the underlying type's operators. By the way, the way to construct a an INT is let a = INT 10, not let a : MYINT = 10.
If you want, you can implement your own addition operator, like so
type MYVAL = INT of int with
static member (+) (INT a, INT b) = INT(a+b)
which would allow you to do
let a = INT 10
let b = INT 25
let c = a+b
You would need to do this for any operator you want to use, e.g. (-), (*), etc.
This might all seem a bit confusing, I mean why wouldn't we want the operators to be generated automatically? Well, if you're writing a parser, you might want to be able to read either an int or a string. Such a parser might output a value of a type type MYVAL = INT of int | STRING of string. How would (+) be defined, then? How about (-)?
In the parser example, MYVAL would no longer be a single case discriminated union, as it has multiple cases. A natural question to ask is, why are single case discriminated unions interesting, then? Who would want to use anything like that? Turns out, it's quite neat for subtyping. Say you want to represent a number that's higher than 10. One way to do this is
type HigherThan10 = private Value of int with
static member TryCreate(x: int) =
if x >= 10
then Some(Value(x))
else None
let x = Value(1) // Error
let y = HigherThan10.TryCreate(1) // None
let z = HigherThan10.TryCreate(10) // Some
I know it's not the most interesting example, but it may be used for representing an email adress as a 'subtype' of string. Notice, by the way, how this avoids using exceptions for control flow by returning a HigerThan10 option.
The reason why a simple sum doesn't work was already explained. I'll just show another option: you could define a map2 function for your type:
type MYVAL =
| INT of int
static member map2 f (INT x) (INT y) = INT (f x y)
//This is the correct way to initialize MYVAL, since it is a single-case discriminated union
let a = INT 10
let b = INT 25
//sum
MYVAL.map2 (+) a b //INT 35
//mult
MYVAL.map2 (*) a b //INT 250
//mod
MYVAL.map2 (%) a b //INT 5
I have this code:
open System
let func<'t when 't:comparison> (a: 't[]) = a
[<EntryPoint>]
let main argv =
let array = [||]
let actual = func array
printfn "array = %A, actual = %A, same objects: %b" array actual (Object.ReferenceEquals(array, actual))
Console.ReadKey()
0
When I try it in LinqPad5 I get a reasonlable error:
Value restriction. The value 'actual' has been inferred to have
generic type val actual : '_a [] when '_a : comparison Either
define 'actual' as a simple data term, make it a function with
explicit arguments or, if you do not intend for it to be generic, add
a type annotation.
However, when I successfully (!) compile and run it (checked for full .NET Framework and DotNetCore both Debug/Release) in Visual Studio I get this output:
array = [||], actual = [||], same objects: false
The only way I could expect this result if 't[] were a value type, but it is definitely not. So, WTF?!?
Decompiled assembly contains this code:
[CompilationMapping(SourceConstructFlags.Module)]
public static class Program
{
public static t[] func<t>(t[] a)
{
return a;
}
[EntryPoint]
public static int main(string[] argv)
{
FSharpTypeFunc fsharpTypeFunc = (FSharpTypeFunc) new Program.array\u00409();
IComparable[] comparableArray = Program.func<IComparable>((IComparable[]) fsharpTypeFunc.Specialize<IComparable>());
FSharpFunc<object[], IComparable[]>.InvokeFast<bool, Unit>((FSharpFunc<object[], FSharpFunc<IComparable[], FSharpFunc<bool, Unit>>>) new Program.main\u004011(ExtraTopLevelOperators.PrintFormatLine<FSharpFunc<object[], FSharpFunc<IComparable[], FSharpFunc<bool, Unit>>>>((PrintfFormat<FSharpFunc<object[], FSharpFunc<IComparable[], FSharpFunc<bool, Unit>>>, TextWriter, Unit, Unit>) new PrintfFormat<FSharpFunc<object[], FSharpFunc<IComparable[], FSharpFunc<bool, Unit>>>, TextWriter, Unit, Unit, Tuple<object[], IComparable[], bool>>("array = %A, actual = %A, same objects: %b"))), (object[]) fsharpTypeFunc.Specialize<object>(), comparableArray, object.ReferenceEquals((object) (object[]) fsharpTypeFunc.Specialize<object>(), (object) comparableArray));
Console.ReadKey();
return 0;
}
[Serializable]
internal sealed class array\u00409 : FSharpTypeFunc
{
[CompilerGenerated]
[DebuggerNonUserCode]
internal array\u00409()
{
}
public override object Specialize<a>()
{
return (object) new a[0];
}
}
[Serializable]
internal sealed class main\u004011\u002D2 : FSharpFunc<bool, Unit>
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CompilerGenerated]
[DebuggerNonUserCode]
public FSharpFunc<bool, Unit> clo3;
[CompilerGenerated]
[DebuggerNonUserCode]
internal main\u004011\u002D2(FSharpFunc<bool, Unit> clo3)
{
this.clo3 = clo3;
}
public override Unit Invoke(bool arg30)
{
return this.clo3.Invoke(arg30);
}
}
[Serializable]
internal sealed class main\u004011\u002D1 : FSharpFunc<IComparable[], FSharpFunc<bool, Unit>>
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CompilerGenerated]
[DebuggerNonUserCode]
public FSharpFunc<IComparable[], FSharpFunc<bool, Unit>> clo2;
[CompilerGenerated]
[DebuggerNonUserCode]
internal main\u004011\u002D1(FSharpFunc<IComparable[], FSharpFunc<bool, Unit>> clo2)
{
this.clo2 = clo2;
}
public override FSharpFunc<bool, Unit> Invoke(IComparable[] arg20)
{
return (FSharpFunc<bool, Unit>) new Program.main\u004011\u002D2(this.clo2.Invoke(arg20));
}
}
[Serializable]
internal sealed class main\u004011 : FSharpFunc<object[], FSharpFunc<IComparable[], FSharpFunc<bool, Unit>>>
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CompilerGenerated]
[DebuggerNonUserCode]
public FSharpFunc<object[], FSharpFunc<IComparable[], FSharpFunc<bool, Unit>>> clo1;
[CompilerGenerated]
[DebuggerNonUserCode]
internal main\u004011(FSharpFunc<object[], FSharpFunc<IComparable[], FSharpFunc<bool, Unit>>> clo1)
{
this.clo1 = clo1;
}
public override FSharpFunc<IComparable[], FSharpFunc<bool, Unit>> Invoke(object[] arg10)
{
return (FSharpFunc<IComparable[], FSharpFunc<bool, Unit>>) new Program.main\u004011\u002D1(this.clo1.Invoke(arg10));
}
}
}
This line seems to be a culprit:
IComparable[] comparableArray = Program.func<IComparable>((IComparable[]) fsharpTypeFunc.Specialize<IComparable>());
If I remove comparison constraint Specialize uses object instead of IComparable.
So, as I've gathered from the comments, your actual question was this:
Why is it that returned object differs from the passed one?
First of all, the expectation of referential identity for values that are logically "equal" is vastly overrated. If your program relies on referential identity, you're doing it wrong. If you have to force referential identity to be preserved everywhere, you end up with Java.
Indeed, try this:
> obj.ReferenceEquals( 5, 5 )
it : bool = false
> obj.ReferenceEquals( [1;2;3], [1;2;3] )
it : bool = false
Huh?
Of course, you may end up with true in some special cases, for example:
> let l = [1,2,3]
> obj.ReferenceEquals( l, l )
it : bool = true
But that's merely a coincidence arising from the specific implementation that the compiler chose to represent your code. Don't rely on it.
Secondly, your function does, in fact, return the "same" (in referential identity sense) object. Try this:
> let x =
let array = [||]
let typedArray : int[] = array
let actual = func typedArray
obj.ReferenceEquals( actual, typedArray )
x : bool = true
See how the "malfunction" disappeared as soon as I created an intermediate typedArray? You can even replace int with IComparable, it will still be true.
The secret is that the function func is actually fine: it does return the "same" object.
The creation of a new object happens not inside func, but every time you reference array.
Try this:
> let x =
let array = [||]
obj.ReferenceEquals( array, array )
x : bool = false
Huh? WTF?!
This happens, because array is not actually an object, but a function behind the scenes. Because you didn't specify what type array was, it must be generic - i.e. have any type that the user wants it to have. This must work:
let array = [||]
let a : int[] = array
let b : string[] = array
Clearly, array cannot have type int[] and type string[] at the same time, so the only way to implement such construct is to compile it as a function that takes no value parameters, but a single type parameter. Kind of like this:
static a[] array<a>() { return new a[0]; }
And then use that function to construct a and b:
var a = array<int>();
var b = array<string>();
And this is exactly what the compiler does. A function that takes only type parameters, one might call it "type function" in this context. And indeed, that's what it's called in compiled code - FSharpTypeFunc.
The key thing that Fyodor mentioned in his answer is that the way F# handles generic values is tricky. You can see that by looking at the following code which compiles fine:
let oops () =
let array = [||]
array.[0] <- 'a'
array.[0] <- 1
Of course, you cannot put both 'a' and 1 in the same array! What happens here is that the compiler actually compiles let array = [||] as a generic function that returns a new empty array when you access it (with a specific instantiation).
Note that this is possible only for simple values that are created without any side-effects. For example, if you wanted to print a message each time the array is accessed, it would not work. The following:
let oops () =
let array = printfn "Creating!"; [||]
array.[0] <- 'a'
array.[0] <- 1
Gives a type error:
error FS0001: This expression was expected to have type
char but here has type
int
This is because the inference engine realised that it cannot compile array as a generic function and, instead, specialized the type based on the first use.
In your case, specializing the type would not cause any problem, because you are not using the generic value with multiple different types. This means that you can make the value the same by adding a side-effect to the creation - or even just ignore a unit value () - which is enough to make the compiler specialize the type:
let func<'t when 't:comparison> (a: 't[]) = a
let same () =
let array = (); [||]
let actual = func array
printfn "same: %b" (Object.ReferenceEquals(array, actual))
let notSame () =
let array = [||]
let actual = func array
printfn "same: %b" (Object.ReferenceEquals(array, actual))
notSame() // same: false
same () // same: true
I guess if someone ever decides to make a Wat talk about F#, this would be a good candidate! The compiler could just disallow all generic values (which is what other ML languages do), but that would remove some useful constructs like Array.empty and replace them with Array.createEmpty ().
I want to create a cacheline sized struct wrapping a mutable, volatile int64 in F#. I’ve tried various struct definitions including the one below, but can't get anything to compile.
[<Struct; StructLayout(LayoutKind.Explicit, Size = 64)>]
type MyStruct1 (initVal:int64) =
[<VolatileField>]
let mutable value = initVal
member x.Value
with get () = value
and set(valIn) = value <- valIn
which gives this error: "Structs cannot contain value definitions because the default constructor for structs will not execute these bindings.
consider adding additional arguments to the primary constructor for the type". I can't see what additional arguements I could add to the primary constructor above.
Any ideas?
The struct definition could be
[<Struct; StructLayout(LayoutKind.Explicit, Size = 64)>]
type MyStruct =
[<FieldOffset(0)>]
val mutable value : int64
new(initVal:int64) = { value = initVal }
member x.Value
with get() = x.value
and set(valIn) = x.value <- valIn
but then, [<VolatileField>] is not allowed on val bindings and structs can't contain let bindings.
TL;DR: AFAIK this is impossible in F#
As pointed out by #V.B. you could use Interlocked which gives a superset of volatiles guarantees (stronger guarantees ≈ more overhead). It might then be better to privateize value to prevent (accidental) writes circumventing the barrier:
[<Struct; StructLayout(LayoutKind.Explicit, Size = 64)>]
type MyStruct =
[<FieldOffset(0)>]
val mutable private value : int64
new(initVal:int64) = { value = initVal }
member public x.Value
with get() = Interlocked.Read(&x.value)
and set(valIn) = Interlocked.Exchange(&x.value, valIn) |> ignore
Interlocked gives similar guarantees as volatile, see this question.
open System.Threading
[<Struct; StructLayout(LayoutKind.Explicit, Size = 64)>]
type MyStruct =
[<FieldOffset(0)>]
val mutable value : int64
new(initVal:int64) = { value = initVal }
member x.Value
with get() = Interlocked.Read(&(x.value))
and set(valIn) = Interlocked.Exchange(&(x.value),valIn) |> ignore
F# has many different ways to define variables/members in types. When should I use let, member val and member this. in F#, and what is the difference between them? How about static and mutable members?
The answer from #meziantou already gives a nice overview of the options (and how they behave differently), so let me just give a brief summary, or list of recommendations:
Use let or let mutable if you want to define a local value that is visible only within the type (essentially a private field or a private function). Inside a module at top-level, these are publicly accessible and evaluated once. let mutable at module level creates a single writable field with no backing value.
You can use val to create an auto-property, it is short for member val Foo = .. with get. From F# this is seen as a field, but it's internally implemented as a get-property with a backing field to prevent mutation.
You can use val mutable to define a public field, but I wouldn't recommend this unless you actually need a public field (e.g. some .NET library may require types with this structure).
Using member x.Foo = ... is the best way to expose (read-only) state from a type. Most F# types are immutable, so this is perhaps the most common public member. It is short for a get-only instance property.
Using member x.Foo with get() = .. and set(value) ... is useful when you need to create a get/set property with your own custom code in the gettor and settor. This is sometimes useful when you're creating a mutable object.
Using member val Foo = ... with get, set is basically the same thing as auto-implemented properties in C#. This is useful if you need a mutable property with a getter and setter that just reads/writes a mutable backing field.
Using static let on a type creates a static (class-level) read-only field, which internally creates a property with a backing field. Use static mutable let ... for a read/write static field without a backing field.
Using static val mutable private creates a static read/write auto-property with a backing field, it cannot be public.
I found out easier to just decompile what's happening, so:
type Region() =
let mutable t = 0.0f
member val Width = 0.0f
member x.Height = 0.0f
member val Left = 0.0f with get,set
member x.Top with get() = 0.0f and set(value) = t <- value
is actually the following:
public class Region
{
internal float t;
internal float Width#;
internal float Left#;
public float Width
{
get
{
return this.Width#;
}
}
public float Height
{
get
{
return 0f;
}
}
public float Left
{
get
{
return this.Left#;
}
set
{
this.Left# = value;
}
}
public float Top
{
get
{
return 0f;
}
set
{
this.t = value;
}
}
public Region() : this()
{
this.t = 0f;
this.Width# = 0f;
this.Left# = 0f;
}
}
This sample explains the difference between syntaxes:
type MyClass() =
let random = new System.Random()
[<DefaultValue>] val mutable field : int
member val AutoProperty = random.Next() with get, set
member this.ExplicitProperty = random.Next()
let c = new MyClass()
// c.random is not accessible
c.field <- 42 // 'field' is accessible
// An automatic property is only evaluated upon initialization, and not every time the property is accessed
printfn "AutoProperty = %d" c.AutoProperty // x
printfn "AutoProperty = %d" c.AutoProperty // Still x
// The value of the explicit property is evaluated each time
printfn "ExplicitProperty = %d" c.ExplicitProperty // y
printfn "ExplicitProperty = %d" c.ExplicitProperty // The value is re-evaluated so you'll get a different value
type VBO<'T when 'T : (new : unit -> 'T) and 'T : struct and 'T :> ValueType> =
{ Handle : int
target : BufferTarget
size : int
dataSize : int
data : 'T []
pos : int
usage : BufferUsageHint }
type VBO =
static member Create(target, size, pos, usage, (data : Vector3 [])) =
VBO.CreateImpl(target, size, pos, usage, Vector2.SizeInBytes, data)
// Type mismatch. Expecting Vector3 but found Vector2
static member Create(target, size, pos, usage, (data : Vector2 [])) =
VBO.CreateImpl(target, size, pos, usage, Vector2.SizeInBytes, data)
// This construct causes code to be less generic than indicated by the type annotations.
// The type variable 'T has been constrained to be type 'Vector3'.
static member CreateImpl(target, size, pos, usage, dataSize, (data : 'T [])) =
let h = GL.GenBuffer()
{ Handle = h
target = target
size = size
dataSize = dataSize
data = data
pos = pos
usage = usage }
F# tries to constrain my code but I want it to be generic. I don't really care about what type the data is I just need it pass in the correct dataSize.
What have I done wrong?
The F# compiler seems to specialise generic types if they are used at a particular instantiation in the same block of code. Try splitting up your declaration like this:
type VBO<'T when 'T : (new : unit -> 'T) and 'T : struct and 'T :> ValueType> =
{ Handle : int
target : BufferTarget
size : int
dataSize : int
data : 'T []
pos : int
usage : BufferUsageHint }
type VBO =
static member CreateImpl(target, size, pos, usage, dataSize, (data : 'T [])) =
let h = GL.GenBuffer()
{ Handle = h
target = target
size = size
dataSize = dataSize
data = data
pos = pos
usage = usage }
type VBO with
static member Create(target, size, pos, usage, (data : Vector3 [])) =
VBO.CreateImpl(target, size, pos, usage, Vector2.SizeInBytes, data)
static member Create(target, size, pos, usage, (data : Vector2 [])) =
VBO.CreateImpl(target, size, pos, usage, Vector2.SizeInBytes, data)
F#'s type inference works top-to-bottom and left-to-right, which occasionally leads to interesting corner cases. In particular, reordering method definitions within a type can affect the inferred types. As Ganesh has pointed out, one solution to your problem is to break your type up into disjoint chunks, but this isn't actually necessary - just putting the generic method first should be sufficient (and note that you can also drop the type annotation on data, if desired).
You can see very similar behavior with simple let rec bindings. Consider:
let rec f() = h 5
and g() = h "test"
and h x = x
When attempting to infer the type of f, the compiler notes that h must take an int as input, which makes g's definition invalid. Reordering the definitions to put h first is the easiest solution (then the compiler can infer a generic type for h before looking at the bodies of f and g, so everything goes through fine).
Alternatively, you can explicitly make h generic and add type annotations to help the compiler out:
let rec f() = h 5
and g() = h "test"
and h<'t> (x:'t) :'t = x
This can be inconvenient since it can require a significant annotation overhead, but there are circumstances where simply reordering definitions is insufficient to allow the compiler to infer the correct types, so it may sometimes be necessary.
I think it is better to look at the code to understand what went wrong.
So here is a simpler example that shows the same problem.
type test =
static member test (data:int) = test.actual(data)
static member test (data:float) =test.actual(data)
static member actual (data:'t) = ()
the problem is that for static member functions, all the types need to be known - or you need a generic type.
I think the simplest solution is to change your code to look like
let actual (data:'t) = ()
type test =
static member test (data:int) = actual(data)
static member test (data:float) =actual(data)
Here, the compiler has much more freedom to alter the let binding to make it generic.