When I tried the console programming, I received unexpected result.
open System
let printSomeMessage =
printfn "Is this the F# BUG?"
[<EntryPoint>]
let main args =
if args.Length = 2 then
printSomeMessage
else
printfn "Args.Length is not two."
0
The printSomeMessage function was included in .cctor() function. Here is IL DASM result.
.method private specialname rtspecialname static
void .cctor() cil managed
{
// Code size 24 (0x18)
.maxstack 4
IL_0000: nop
IL_0001: ldstr "Is this the F# BUG\?"
IL_0006: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5<class [FSharp.Core]Microsoft.FSharp.Core.Unit,class [mscorlib]System.IO.TextWriter,class [FSharp.Core]Microsoft.FSharp.Core.Unit,class [FSharp.Core]Microsoft.FSharp.Core.Unit,class [FSharp.Core]Microsoft.FSharp.Core.Unit>::.ctor(string)
IL_000b: call !!0 [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::PrintFormatLine<class [FSharp.Core]Microsoft.FSharp.Core.Unit>(class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4<!!0,class [mscorlib]System.IO.TextWriter,class [FSharp.Core]Microsoft.FSharp.Core.Unit,class [FSharp.Core]Microsoft.FSharp.Core.Unit>)
IL_0010: dup
IL_0011: stsfld class [FSharp.Core]Microsoft.FSharp.Core.Unit '<StartupCode$FSharpBugTest>'.$Program::printSomeMessage#3
IL_0016: pop
IL_0017: ret
} // end of method $Program::.cctor
So, its execution result is like this.
Is this the F# BUG?
Args.Length is not two.
Am I missing some grammar or F# characteristic? Or F# builder’s BUG?
No it's a bug in your code. You need to add parentheses after "printSomeMessage", otherwise printSomeMessage is a simple value rather than a function.
open System
let printSomeMessage() =
printfn "Is this the F# BUG?"
[<EntryPoint>]
let main args =
if args.Length = 2 then
printSomeMessage()
else
printfn "Args.Length is not two."
0
Simple values are initialized in the constructor of a module, so you see your code being called when the module is initialized. This is logical when you think about it, the normal case of simple values would be binding a string, integer, or other literal value to an identifier. You would expect this to happen a start up. i.e. the following will be bound at module start up:
let x = 1
let y = "my string"
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... :-)
Consider the following F#:-
type TestClass() =
let getValFromMap m k = Map.find k m
let addToMap map k i = map |> Map.add k i
let mutable someMap : Map<string,int> = Map.empty
let getValFromMapPartial key = getValFromMap someMap key
let getValFromMapPartialAndTacit = getValFromMap someMap
member this.AddThenGet() =
someMap <- addToMap someMap "A" 10
let value = getValFromMapPartial "A"
printfn "Value from partial = %i" value // prints out
let value = getValFromMapPartialAndTacit "A" // throws
printfn "Value from partial and tacit = %i" value
[<EntryPoint>]
let main argv =
let test = TestClass()
test.AddThenGet()
0
Functions getValFromMapPartial and getValFromMapPartialAndTacit are, to my mind, identical. F# says they have the exact same type: (string -> int). And yet they behave very differently, and they are compiled very differently. Decompiling using dotPeek, I see that getValFromMapPartial is a method, whereas getValFromMapPartialAndTacit is a field that is initialized in the ctor.
F# does not complain about getValFromMapPartialAndTacit, even on the highest warning level (both in VS 2012 and 2013). And yet calling this function in my sample above fails, presumably because it has wrapped the initial, empty version of the someMap, despite its mutability.
Why is there a difference between these two functions? Should there be a warning from F# that the tacit / point-free version might fail?
The F# compiler distinguishes between let-bindings of functions, which have parameters, and values, which do not have parameters.
Value definition: A binding like let a = ... is a value definition. Its body is evaluated eagerly, "where it is", before the evaluation of anything further down the code.
Function definition: A binding like let f x = ... is a syntactic function definition, the contents of which are evaluated when the function is called.
Since someMap refers to a mutable variable, using this variable inside a function definition means reading from the variable when the function is called. However, the usage in getValFromMapPartialAndTacit reads the value at the moment of declaration.
This behavior does not stop a value from being a function. You could just as well write let f = fun x -> ... to declare a function, and ... would again be part of a function definition. However, if you were to add definitions in between the = and fun, they would be evaluated at the point of the definition of f, not when it is called.
In the question's comments, the same problem occurs with someMap being a mutable reference cell. This is the same problem. The function, as rewritten by Andrew for a mutable reference cell:
let getValFromMapPartialAndTacit = getValFromMap !someMap
Here, the dereference operator (!) is applied when the value is bound, not when the function is called. it is equivalent to:
let mapRightNow = !someMap
let getValFromMapPartialAndTacit = getValFromMap mapRightNow
getValFromMapPartial is a true syntactic function. Its signature is val getValFromMapPartial : key:string -> int. Whenever it is called, it uses the current value of someMap. That's why it works in your example; it accesses the version of someMap who has an entry.
On the other hand, getValFromMapPartialAndTacit is a lambda-computing function. Its signature is val getValFromMapPartialAndTacit : (string -> int) (notice the parentheses). The lambda has a compiler-generated closure, which contains the version of someMap at the time the lambda was computed. That's why it does not work in your example; it always acesses the same, original version of someMap who has no entry.
I need to do some setup in a module that I wanted to accomplish by leveraging a do block. Strangely though, my do block never seems to get hit.
Even stranger, If I load the module code into fsi, it does get hit. Here is my example:
Main.fs
[<EntryPoint>]
let main args =
printfn "%b" TestNamespace.M.x
0
TestModule.fs
namespace TestNamespace
module M =
do
printfn "In do"
failwith "Error" // this is line 6
let x = true
When I run the compiled executable I get
>test.exe
true
Why didn't the exception get thrown? If I run the module in FSI by itself I get
In do
System.Exception: Error
at <StartupCode$FSI_0006>.$FSI_0006.main#() in C:\Projects\Personal2\Playground\fsscripts\fsscripts\TestModule.fs:line 6
Stopped due to error
So it got the exception.
I see that in the decompliation that the do initializers get rolled into a seperate class
namespace \u003CStartupCode\u0024fsscripts\u003E
{
internal static class \u0024Library1
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CompilerGenerated]
[DebuggerNonUserCode]
internal static int init\u0040;
static \u0024Library1()
{
ExtraTopLevelOperators.PrintFormatLine<Unit>((PrintfFormat<Unit, TextWriter, Unit, Unit>) new PrintfFormat<Unit, TextWriter, Unit, Unit, Unit>("In do"));
Operators.FailWith<Unit>("Error");
bool x = M.x;
}
}
}
VS the actual module code:
namespace TestNamespace
{
[CompilationMapping(SourceConstructFlags.Module)]
public static class M
{
public static bool x
{
[DebuggerNonUserCode] get
{
return true;
}
}
}
}
So how do I make sure the do block actually gets executed?
--
Edit, given the above example counts as a simple constant expression so won't produce an observable initialization, why does the following also not work?
[<EntryPoint>]
let main args =
printfn "%d" (TestNamespace.M.x id 1)
0
namespace TestNamespace
module M =
do
printfn "In do"
failwith "Error"
let x f a = f a
This prints out 1 no problem.
Edit, after having re-read Tomas's comments its because a function is considered a constant expression.
For a good explanation of the problem, see the answer to this previous SO question. The important bit says:
the static initializer for the file is executed on first access of a value that has observable initialization
Now, "observable initialization" is somewhat tricky idea, but simple constant initialization definitely does not have observable initialization - that's why the do block is not executed. You can trick the compiler into thinking that there is some imperative action, for example by adding do ():
module M =
do
printfn "In do"
failwith "Error" // this is line 6
let x = (do ()); true
You can get the behavior you want, while maintaining the same public interface, with a class:
type M private () =
static do
printfn "In do"
failwith "Error"
static member val x = true
Here is a clean way to do it.
First, note that if you wanted the initialization code to run every time the function is called, you would do this:
module M =
let init () =
printfn "In init"
let x f a =
init ()
printfn "In x"
f a
So, if you want it to be called just once (static initialization), you can simply remove the () from both places:
module M =
let init =
printfn "In init"
let x f a =
init
printfn "In x"
f a
The nice thing is that you have documented your design that the init code will be called first. If you have several separate blocks of initialization code, it is clear which dependency you are relying on (although the first initialization will execute all such blocks of course).
UPDATE
Here is a version, which works in a Release build too. Not quite so clean, but almost:
module Init =
open System.Runtime.CompilerServices
[<MethodImpl(MethodImplOptions.NoInlining)>]
let call init = init
module M =
let init =
printfn "In init"
let x f a =
Init.call init
printfn "In x"
f a
Note that init is still a unit value, so Init.call is a non-inlined function that does nothing at all. So there is the overhead of a function call to nothing.
An alternative, which also works but seems a little strange is this:
module M =
let mutable init =
printfn "In init"
let x f a =
init <- init
printfn "In x"
f a
Can anyone improve on this?
define a function that has a single parameter of type string which which displayed on console. invoke the function passing it a message. ensure the function ignores any returned value
open System
let NoReturnFunction msg =
Console.WriteLine(string(msg))
NoReturnFunction "Hello World"
I am in a trouble to how to avoid return value of function
In this case there is no work to do because the WriteLine method doesn't return any values. It's a void returning function. In general though the way to ignore a return value in F# is to use the ignore function.
1 + 2 |> ignore
Couple of minor nit picks on the your code sample. The first is you can avoid the cast to string by simply typing the parameter. Second in F# it's more idiomatic to use the printfn function instead of Console.WriteLine
let NoReturnFunction (msg : string) =
printfn "%s" msg
For sake of completeness, you can also let F# infer the parameter type and the return type--like so:
let NoReturnFunction st = printfn "%s" st
This infers the type of s and the return type of NoReturnFunction (unit in this case).
I am trying to set the message formatter for a message in F#. In C# I can have:
foreach (System.Messaging.Message message in messages)
{
message.Formatter = new XmlMessageFormatter(new String[] { "System.String,mscorlib" });
string body = message.Body.ToString();
Console.WriteLine(body);
}
which works just fine. I now want to do the same thing in F# and have:
let mList = messageQueue.GetAllMessages()
let xt = [| "System.String,mscorlib" |]
for m in mList do
m.Formatter = XmlMessageFormatter(xt)
which causes this error at compile time:
Error 2 This expression was expected to have type
IMessageFormatter
but here has type
XmlMessageFormatter
I suspect I am missing a basic concept in F#. What am I doing wrong?
--EDIT--
latkin's answer worked perfectly. Just in case anyone else is interested, here is the full working program in F#:
open System.Messaging
[<EntryPoint>]
let main argv =
printfn "%A" argv
let messageQueue = new MessageQueue(".\private$\Twitter")
messageQueue.MessageReadPropertyFilter.SetAll();
let mList = messageQueue.GetAllMessages()
let xt = [| "System.String,mscorlib" |]
for m in mList do
m.Formatter <- XmlMessageFormatter(xt)
printfn "%s " (m.Body.ToString())
0 // return an integer exit code
When you are assigning a mutable value, the operator is <-, not =. In F# = is only used for initial bindings, otherwise it's used as the Boolean equality operator (like C-family ==). Some docs here.
You want
let mList = messageQueue.GetAllMessages()
let xt = [| "System.String,mscorlib" |]
for m in mList do
m.Formatter <- XmlMessageFormatter(xt)
No casting is needed in this case.
The error comes up because the compiler thinks you are trying to compare a IMessageFormatter to a XmlMessageFormatter.
F# doesn't have implicit casts like C# does, so it doesn't automatically upcast your XmlMessageFormatter to the IMessageFormatter used by the Formatter property.
There was a similar question a couple of days ago with more information about this:
F# return ICollection