Let's consider this code:
type TransactionTypes =
| TransactionType1
| TransactionType2
type Test() =
let mutable lastTransactionType1 = DateTime.MinValue
let mutable lastTransactionType2 = DateTime.MinValue
let getLastTransaction transaction =
match transaction with
| TransactionType1 -> lastTransactionType1
| TransactionType2 -> lastTransactionType2
let updateLastTransaction transaction =
match transaction with
| TransactionType1 -> lastTransactionType1 <- DateTime.UtcNow
| TransactionType2 -> lastTransactionType2 <- DateTime.UtcNow
Now (with the understanding that I'm still learning F#), I would like to clarify a couple things:
Something like:
let a = DateTime.Now
does a permanent binding, so 'a' will always be the same time on subsequent uses.
But, my understanding is that if there is a parameter, like:
let a anyParameter = DateTime.Now
will be re-evaluated every time due to the presence of the parameter. Is that correct?
In the code above, the two let statements (getLastTransaction and updateLastTransaction) are private to the type (Test)
I could also have implemented them as:
member private this.getLastTransaction = ...
member private this.updateLastTransaction = ...
Is there any reason, for private functions to prefer let vs. member private this?
"let mutable" already implies the this. so the fields are accessible by both forms.
So, what is the advantage of one form vs. the other?
When you are working with members, F# inherits a lot of things from the .NET object model. A .NET object can have a couple of different things:
Fields - those are storing a value (just like fields of a record). They can be mutable or immutable.
Methods - those can be invoked with zero or more arguments (like functions)
Properties - those have no arguments (like fields); they can be read or written, but when this happens, some code is invoked. A property is basically a pair of getter and setter methods.
In F#, some of this is less visible. However, let corresponds to a field and member with arguments corresponds to a method. Your tricky case is a member without arguments. For example:
type A() =
member x.Foo = printfn "Hi"; 42
Will Hi be printed only once, or will it be printed each time you access Foo? To answer, it's useful to know that Foo is a property with a getter. The above is actually a syntactic sugar for the full version:
type A() =
member x.Foo
with get() = printfn "Hi"; 42
Now you can see that there is a method behind the Foo property! Each time you access Foo, the compiler will generate a call to the get() method, so Hi will be printed repeatedly.
In addition to Tomas' answer:
let mutable lastTransactionType1 = DateTime.MinValue
is equivalent in C# to:
internal DateTime lastTransactionType1 = DateTime.MinValue;
and
member private this.getLastTransaction ...
is the same IL as far as IL is concerned with
let getLastTransaction ...
In equivalent C#, both are
internal DateTime getLastTransactionMember(TransactionTypes transaction)
{
if (transaction.Tag != 1)
{
return lastTransactionType1;
}
return lastTransactionType2;
}
But for using F# in an idiomatic way, you would want to go with let.
There's also a difference in that member does let you use the methods in bindings before their declaration, which might be useful in some cases (read: hacks)
let getType1 = this.getLastTransactionMember TransactionType1 //this compiles
member private this.getLastTransactionMember transaction =
match transaction with
| TransactionType1 -> lastTransactionType1
| TransactionType2 -> lastTransactionType2
Related
I'm learning me some F#, and I'm trying to figure out how constructors work.
I want to write a class that takes some input data, parses it, and makes the results available to the outside world via member variables. The parsing process is non-trivial, so I want to create some local variables along the way, but how can I do that without them becoming private member variables, as well? AFAICT, using let to create a private member variable is almost the same as using member private, but I don't want these temporary variables to pollute the object's namespace.
This is the best I've been able to come up with, so far:
type MyClass( inputData ) =
let _parsedData =
// simulate expensive parsing of the input data
let work = sprintf "< %s >" inputData
sprintf "[%s]" work
member this.parsedData = _parsedData
member this.dump () =
// this doesn't compile (as expected)
//printfn "work = %s" work
// I want this to *not* compile (because _parsedData is a local variable in the constructor)
printfn "_parsedData = %s" _parsedData
[<EntryPoint>]
let main argv =
let obj = MyClass "hello, world!"
printfn "obj.parsedData = %s" obj.parsedData
obj.dump()
0
But _parsedData becomes a private member variable, which is not necessary since it's just a temporary working variable, and the final value is stored in this.parsedData. The SO post I linked to above suggests that variables created using let will act as local variables and be discarded, as long as they are not referenced in other members, but the act of defining this.parsedData to return _parsedData is enough to keep _parsedData alive.
I could use lazy evaluation:
let _parsedDataLazy = lazy (
// simulate expensive parsing of the input data
let work = sprintf "< %s >" inputData
sprintf "[%s]" work
)
member this.parsedDataLazy = _parsedDataLazy.Value
but this doesn't really help, since it still has the problem of _parsedDataLazy becoming a private member variable (although in this case, it makes sense). This approach also means keeping inputData alive until the first time parsedDataLazy is called, which may not be desirable/possible.
I also thought of using val to define the member variable, then execute the parsing code to populate it, but do bindings have to appear before any member's :-/
I just want to be able to use local variables in a constructor, to calculate a value, then store it in the object. Why does let create a private member variable, given that there's already a way of doing that?! The purpose of a constructor is to initialize the object being created, it's just a function, so I don't get why there are these special restrictions on when code can be executed, or different behaviour (e.g. if I use let to define a new variable in a member function, it doesn't get hoisted into the object as a member variable).
As an aside, if I create a private member variable in the constructor using let, like this:
let _foo = 42
then I access it like this:
let member this.printFoo () =
printfn "_foo = %s" _foo // no "this"
But if I create it like this:
member private _foo = 42
then I access it like this:
let member this.printFoo () =
printfn "_foo = %s" this._foo // uses "this"
This different syntax suggests that the former is creating a closure over the constructor, and keeping the _foo variable alive for the life of the object, rather than _foo actually being member of the object. Is this what's actually happening?
To answer #konst-sh's question "why do you think it should be evaluated on every call?", I don't think it should, but that's not what I'm seeing.
My understanding is that for the code below, the 3 statements that make up parsedData are an expression, that evaluates to a string (the output of sprintf), that is stored in a member variable.
type MyClass( inputData ) =
member this.parsedData =
// simulate expensive parsing of the input data
printfn "PARSE"
let work = sprintf "< %s >" inputData
sprintf "[%s]" work
[<EntryPoint>]
let main argv =
let obj = MyClass "hello, world!"
printfn "CONSTRUCTED"
printfn "obj.parsedData = %s" obj.parsedData
printfn "obj.parsedData = %s" obj.parsedData
0
But when I run it, I get this:
CONSTRUCTED
PARSE
obj.parsedData = [< hello, world! >]
PARSE
obj.parsedData = [< hello, world! >]
I would expect to see this:
PARSE
CONSTRUCTED
obj.parsedData = [< hello, world! >]
obj.parsedData = [< hello, world! >]
Stepping through in VSCode also confirms that the 3 statements get executed twice. But parseData is not a function, right? For that, I would need to define it like this:
member this.parsedData () =
...
It feels like I'm missing something fundamental here... :-)
I have a Discriminated Union ("DU") type and a property OR method which computes something based on the DU instance. I am trying to achieve a pattern where the instance property performs the calculation the first time it is requested and then remembers the result - akin to a Singleton Pattern in Object Oriented Terms.
I am finding this challenging without the aid of a local instance variable to store the state of things...
I have tried simple memoization of a method but I then run into the problem of not having anywhere (in the instance) to store the memoized result.
Note: there will be many instances of this DU type in my application.
Code
// Terrible mutable variable needed alongside the DU to achieve a singleton-like pattern
let mutable result: int option = None
type DU =
| Good of int
| Bad of int
with
// behaves like a Singleton
member this.GetSomething =
match result with
| None ->
printfn "Big bad side-effect to let us know it's a first time"
// big bad calculation that we only want to do once
let x = 1 + 1
// "memoize" it
result <- Some x
x
| Some y -> y
let instance = Good 1
let f1 = instance.GetSomething // first time
let f2 = instance.GetSomething // second call - no side effect1
You can't memoize inside of an immutable value, because memoization involves changing and maintaining state.
Obviously, you can do it outside of an immutable value:
let smth = getSomething "foo"
As long as you reuse smth instead of calling getSomething "foo" again, you've essentially memoized the result. This is safe if getSomething is referentially transparent; otherwise, it's not.
From the sample code posted in the OP, it looks more like you're looking for lazy initialization, which you can get from the Lazy<T> class. You'll still need an object in which to store the Lazy<T> instance, though.
open System
type MyObject() =
let result =
lazy
printfn "Big bad side-effect to let us know it's a first time"
// big bad calculation that we only want to do once
1 + 1
member this.GetSomething = result.Value
As you can see, in F# you can also use lazy expressions for this.
> let mo = MyObject ();;
val mo : MyObject
> let smth1 = mo.GetSomething;;
Big bad side-effect to let us know it's a first time
val smth1 : int = 2
> let smth2 = mo.GetSomething;;
val smth2 : int = 2
The MyObject class may look immutable, but that's only because state is being kept inside of the lazy expression.
This way it is possible to have a lazy inside a DU.
Because the type is Lazy.
type DU =
| Good of Lazy<int> // Lazy not lazy
| Bad of Lazy<int>
type MyObject() =
let result =
lazy(
printfn "Big bad side-effect to let us know it's a first time"
// big bad calculation that we only want to do once
1 + 1) |> Good
member this.GetSomething = result
let mo = MyObject()
let f() =
match mo.GetSomething with
| Good x -> x.Value
| Bad y -> y.Value
f()
f()
Output
Big bad side-effect to let us know it's a first time
val it : int = 2
>
val it : int = 2
For the sample program:
type public MyClass(reasonForLiving:string) =
member x.ReasonForLiving with get() = reasonForLiving
let classFactory () = MyClass("up to you")
let live () =
let instance = classFactory()
if instance = null then raise(System.Exception("null is not living... that's why OO languages die from bugs"))
instance
I get the error "The type 'MyClass' does not have null as a proper value" when I go to use this class as a return value of implicitly typed functions and compare it to null (b/c of compatibility requirements with C# dependency injection I cannot rely on F# option types).
I can easily fix this by changing the null check to:
if instance :> obj = null then
However, I know ("feel") this is completely "wrong". Especially when I consider how MyClass is a reference type that shouldn't need to be boxed (speaking from a C# background).
I've read about "F# Value Restriction" and how it impacts type inference, but I can't seem to gleam how it applies to this scenario.
Q: Is there another way to do this?
Aside #1: I found a simpler method of getting the error...
type public MyClass(reasonForLiving:string) =
member x.ReasonForLiving with get() = reasonForLiving
let nullMyClass : MyClass = null
Aside #2: I did try System.Nullable without thinking... MyClass is a reference type and not a value type (struct) which Nullable<_> requires. So, just reassures me that I REALLY am dealing with a reference type and leaves me wondering why an object cast suddenly makes this work.
Update: For anyone interested, I used this as one solution for Common Service Locator with the three functions below. Each service requested must support null, so if the service class is defined in F#, you need to add the [<AllowNullLiteral>]:
let private getServiceLocator () =
try Some(Microsoft.Practices.ServiceLocation.ServiceLocator.Current)
with | _ -> None
let private getService serviceFactory =
let serviceLocator = getServiceLocator()
let service = match serviceLocator with
| None -> serviceFactory()
| _ ->
match serviceLocator.Value.GetInstance<'a>() with
| null -> serviceFactory()
| svc -> svc
match service with
| null -> None
| _ -> Some(service)
let private getRequiredService serviceFactory =
let service = getService serviceFactory
match service with
| None -> raise(MissingServiceException(""))
| _ -> service.Value
Use the [<AllowNullLiteral>] attribute:
[<AllowNullLiteral>]
type public MyClass(reasonForLiving:string) =
member x.ReasonForLiving with get() = reasonForLiving
By default, F# types do not allow null (thank heavens!). This attribute is useful for interop with other .NET languages and allows assignment/comparison with null.
The problem with the AllowNullLiteral attribute is that in addition to allowing you to compare your objects to null, it also makes it possible to set your objects to null.
Assuming that this is not desirable for your use-case, there is an easy alternative with unobservable performance impact:
let inline isNull (x:^T when ^T : not struct) = obj.ReferenceEquals (x, null)
Then rather than doing if instance = null then, do if isNull instance then instead.
This will work for any reference type (including records and DUs), but does not introduce the possibility of setting objects of your F# types to null from F# – the best of both worlds.
I would like to define a type such as:
type blah =
AThing
| AnotherThing
with
static member ofString : string -> blah
override x.ToString () : string
I would like to make sure that the two methods are always guaranteed to be consistent. A good way of doing this would be to construct two maps from the same list of pairs, and then turn them into the obvious implementations of the two methods. Roughly:
let pairs = [Athing, "AThing"; AnotherThing, "AnotherThing"]
let tostr = Map.ofList pairs
let toblah = pairs |> List.map swap |> Map.ofList
I think this code can only be defined in a static member function. The static bit is implied by it needing to be accessible from ofString, which is static. It cannot be defined before the type, since the list relies on it. It cannot be defined afterwards because F# does not allow methods to be just declared and implemented later (in the same way that e.g. C++ would). So that leaves the choice between a static member and a static let. The compiler says that static lets are not allowed in an augmentation. (?)
The code works fine when put into a static member function, however it makes the maps every time they are needed. Needless to say, this is even less efficient than linear search. How do I do it correctly please? Many thanks.
This compiles (with a warning)
type blah =
AThing
| AnotherThing
let pairs = [AThing, "AThing"; AnotherThing, "AnotherThing"]
let tostr = Map.ofList pairs
let toblah = pairs |> List.map (fun (x,y)->y,x) |> Map.ofList
type blah
with
static member ofString s = toblah.[s]
override x.ToString () = tostr.[x]
and demonstrates an augmentation (define the type, do other code, then do type blah with to define more members).
Here's the code that works as required:
type blahFactory() =
static let pairs = printf "array initialized; "; [AThing, "AThing"; AnotherThing, "AnotherThing"]
static member tostr = Map.ofList pairs
static member toblah = pairs |> List.map swap |> Map.ofList
and blah =
| AThing
| AnotherThing
with
static member ofString (string) = blahFactory.toblah.[string]
override x.ToString () = blahFactory.tostr.[x]
I've placed printf instruction to demonstrate the array is initialized just once.
Several thoughts you may consider useful.
First, using DU is overhead for sample provided. If your data is that simple, you may consider enum types.
If you really mean DU, that may be sign of possible problems in the future. Consider this:
type blah =
| AThing of string
| AnotherThing of int * int
Both construction and comparison will be impossible in this case.
Do you have any reasons not to use standard XML serialization?
I don't get your point. What's wrong with:
type blah =
| AThing
| AnotherThing
with
static member ofString = function
| "AThing" -> AThing
| "AnotherThing" -> AnotherThing
| _ -> failwith "Unwellformed string"
override x.ToString () =
match x with
| AThing -> "AThing"
| AnotherThing -> "AnotherThing"
Pattern matching is Θ(1) which is extremely efficient in F#.
I believe you were trying to do the following: for any Discriminated Union have an ability to go from particular DU case to its name and back without burden of hardcoding the relationship for each pair, which have place in both answers by Brian and pad.
If you sacrifice override of ToString() in lieu of the equivalent static member it can be done with the following approach:
open Microsoft.FSharp.Reflection
type Blah =
| AThing
| AnotherThing
[<AutoOpenAttribute>]
module BlahExt =
let cases = FSharpType.GetUnionCases typeof<Blah>
let toBlah = dict [for case in cases do yield (case.Name, FSharpValue.MakeUnion(case, [||]) :?> Blah)]
let fromBlah = dict [for case in cases do yield ((FSharpValue.MakeUnion(case, [||]) :?> Blah), case.Name)]
type Blah
with
static member ofString name =
if toBlah.ContainsKey name then (toBlah.Item name) else failwith "bad string"
static member toString x = fromBlah.Item x
Now printfn "ofString: %A" (Blah.ofString "AThing") shows union case AThing and vice versa printfn "toString: %s" (Blah.toString AThing) shows string AThing.
You can notice that I did not list members of your DU whatsoever, this is achieved once thru reflection and guaranteed to be correct mapping automagically. This approach will work for any number of unit cases - two or two hundreds - without any need to hardcode the particular cases.
I know virtually nothing about F#. I don’t even know the syntax, so I can’t give examples.
It was mentioned in a comment thread that F# can declare functions that can take parameters of multiple possible types, for example a string or an integer. This would be similar to method overloads in C#:
public void Method(string str) { /* ... */ }
public void Method(int integer) { /* ... */ }
However, in CIL you cannot declare a delegate of this form. Each delegate must have a single, specific list of parameter types. Since functions in F# are first-class citizens, however, it would seem that you should be able to pass such a function around, and the only way to compile that into CIL is to use delegates.
So how does F# compile this into CIL?
This question is a little ambiguous, so I'll just ramble about what's true of F#.
In F#, methods can be overloaded, just like C#. Methods are always accessed by a qualified name of the form someObj.MethodName or someType.MethodName. There must be context which can statically resolve the overload at compile-time, just as in C#. Examples:
type T() =
member this.M(x:int) = ()
member this.M(x:string) = ()
let t = new T()
// these are all ok, just like C#
t.M(3)
t.M("foo")
let f : int -> unit = t.M
let g : string-> unit = t.M
// this fails, just like C#
let h = t.M // A unique overload for method 'M' could not be determined
// based on type information prior to this program point.
In F#, let-bound function values cannot be overloaded. So:
let foo(x:int) = ()
let foo(x:string) = () // Duplicate definition of value 'foo'
This means you can never have an "unqualified" identifier foo that has overloaded meaning. Each such name has a single unambiguous type.
Finally, the crazy case which is probably the one that prompts the question. F# can define inline functions which have "static member constraints" which can be bound to e.g. "all types T that have a member property named Bar" or whatnot. This kind of genericity cannot be encoded into CIL. Which is why the functions that leverage this feature must be inline, so that at each call site, the code specific-to-the-type-used-at-that-callsite is generated inline.
let inline crazy(x) = x.Qux(3) // elided: type syntax to constrain x to
// require a Qux member that can take an int
// suppose unrelated types U and V have such a Qux method
let u = new U()
crazy(u) // is expanded here into "u.Qux(3)" and then compiled
let v = new V()
crazy(v) // is expanded here into "v.Qux(3)" and then compiled
So this stuff is all handled by the compiler, and by the time we need to generate code, once again, we've statically resolved which specific type we're using at this callsite. The "type" of crazy is not a type that can be expressed in CIL, the F# type system just checks each callsite to ensure the necessary conditions are met and inlines the code into that callsite, a lot like how C++ templates work.
(The main purpose/justification for the crazy stuff is for overloaded math operators. Without the inline feature, the + operator, for instance, being a let-bound function type, could either "only work on ints" or "only work on floats" or whatnot. Some ML flavors (F# is a relative of OCaml) do exactly that, where e.g. the + operator only works on ints, and a separate operator, usually named +., works on floats. Whereas in F#, + is an inline function defined in the F# library that works on any type with a + operator member or any of the primitive numeric types. Inlining can also have some potential run-time performance benefits, which is also appealing for some math-y/computational domains.)
When you're writing C# and you need a function that can take multiple different parameter sets, you just create method overloads:
string f(int x)
{
return "int " + x;
}
string f(string x)
{
return "string " + x;
}
void callF()
{
Console.WriteLine(f(12));
Console.WriteLine(f("12"));
}
// there's no way to write a function like this:
void call(Func<int|string, string> func)
{
Console.WriteLine(func(12));
Console.WriteLine(func("12"));
}
The callF function is trivial, but my made-up syntax for the call function doesn't work.
When you're writing F# and you need a function that can take multiple different parameter sets, you create a discriminated union that can contain all the different parameter sets and you make a single function that takes that union:
type Either = Int of int
| String of string
let f = function Int x -> "int " + string x
| String x -> "string " + x
let callF =
printfn "%s" (f (Int 12))
printfn "%s" (f (String "12"))
let call func =
printfn "%s" (func (Int 12))
printfn "%s" (func (String "12"))
Being a single function, f can be used like any other value, so in F# we can write callF and call f, and both do the same thing.
So how does F# implement the Either type I created above? Essentially like this:
public abstract class Either
{
public class Int : Test.Either
{
internal readonly int item;
internal Int(int item);
public int Item { get; }
}
public class String : Test.Either
{
internal readonly string item;
internal String(string item);
public string Item { get; }
}
}
The signature of the call function is:
public static void call(FSharpFunc<Either, string> f);
And f looks something like this:
public static string f(Either _arg1)
{
if (_arg1 is Either.Int)
return "int " + ((Either.Int)_arg1).Item;
return "string " + ((Either.String)_arg1).Item;
}
Of course you could implement the same Either type in C# (duh!), but it's not idiomatic, which is why it wasn't the obvious answer to the previous question.
Assuming I understand the question, in F# you can define expressions which depend on the availability of members with particular signatures. For instance
let inline f x a = (^t : (member Method : ^a -> unit)(x,a))
This defines a function f which takes a value x of type ^t and a value a of type ^a where ^t has a method Method taking an ^a to unit (void in C#), and which calls that method. Because this function is defined as inline, the definition is inlined at the point of use, which is the only reason that it can be given such a type. Thus, although you can pass f as a first class function, you can only do so when the types ^t and ^a are statically known so that the method call can be statically resolved and inserted in place (and this is why the type parameters have the funny ^ sigil instead of the normal ' sigil).
Here's an example of passing f as a first-class function:
type T() =
member x.Method(i) = printfn "Method called with int: %i" i
List.iter (f (new T())) [1; 2; 3]
This runs the method Method against the three values in the list. Because f is inlined, this is basically equivalent to
List.iter ((fun (x:T) a -> x.Method(a)) (new T())) [1; 2; 3]
EDIT
Given the context that seems to have led to this question (C# - How can I “overload” a delegate?), I appear not to have addressed your real question at all. Instead, what Gabe appears to be talking about is the ease with which one can define and use discriminated unions. So the question posed on that other thread might be answered like this using F#:
type FunctionType =
| NoArgument of (unit -> unit)
| ArrayArgument of (obj[] -> unit)
let doNothing (arr:obj[]) = ()
let doSomething () = printfn "'doSomething' was called"
let mutable someFunction = ArrayArgument doNothing
someFunction <- NoArgument doSomething
//now call someFunction, regardless of what type of argument it's supposed to take
match someFunction with
| NoArgument f -> f()
| ArrayArgument f -> f [| |] // pass in empty array
At a low level, there's no CIL magic going on here; it's just that NoArgument and ArrayArgument are subclasses of FunctionType which are easy to construct and to deconstruct via pattern matching. The branches of the pattern matching expression are morally equivalent to a type test followed by property accesses, but the compiler makes sure that the cases have 100% coverage and don't overlap. You could encode the exact same operations in C# without any problem, but it would be much more verbose and the compiler wouldn't help you out with exhaustiveness checking, etc.
Also, there is nothing here which is particular to functions; F# discriminated unions make it easy to define types which have a fixed number of named alternatives, each one of which can have data of whatever type you'd like.
I'm not quite sure that understand your question correctly... F# compiler uses FSharpFunc type to represent functions. Usually in F# code you don't deal with this type directly, using fancy syntactic representation instead, but if you expose any members that returns or accepts function and use them from another language, line C# - you will see it.
So instead of using delegates - F# utilizes its special type with concrete or generic parameters.
If your question was about things like add something-i-don't-know-what-exactly-but-it-has-addition-operator then you need to use inline keyword and compiler will emit function body in the call site. #kvb's answer was describing exactly this case.