F#: get source files to evaluate automatically - f#

I'm making a project where there are separate source files/modules that add functions to a single Dictionary contained in a higher level file. However, I find that nothing in these source files evaluates on its own, even functions that take no arguments/code that isn't even inside a function.
As a result nothing is being added to the Dictionary. Is there a way to forcibly evaluate complete function calls in a module automatically? I'll give an example of what I'm trying to do:
Registry.fs:
let private functions = Dictionary<string, MessageHandler>()
let add type handler =
functions.Add(type, handler)
Handler1.fs:
Registry.add "type1" (fun m -> ....
)
Handler2.fs:
Registry.add "type2" (fun m -> ....
)

I believe you need to see this relevant topic. Loose method calls would get compiled as method calls inside of a static constructor for the enclosing type/module, when the F# code gets compiled to IL. This would roughly be equivalent to the following C# code, just to see the picture:
static class Handler1 {
static Handler1() {
// this is the static constructor
Registry.add "type1" ....
}
}
In .NET static constructors are not eagerly initialized1. This means, if you want to cause the .NET runtime to call the Handler1 static constructor, you need to access a static member of the type Handler1.
An example of using the type in a static context would be to
Expose a sufficiently accessible static member/method:
module Handler1 =
[<Literal>]
let Name = "Handler1"
Access that static member from your code, such as the main method:
[<EntryPoint>]
let main args =
printf Handler1.Name
The above line will force the .NET runtime to load the Handler1 type's static context, which will result in invoking the static constructor if the type is encoutered by your code for the first time. If your code never encounters a given type's static context (any static member or method), then it will never be initialized -- the static constructors will never get called.
This behaviour is by design of the .NET framework (and that is regardless of the chosen language -- C#, F#, VB, others -- they all compile to similar IL). The point is to not allocate unnecessary resources by types that are never actually used.
1 Until .NET 4, static type context was initialized when the given type was first encountered by the executing code, regardless if the user code is interacting with instace or static members of that type. After .NET 4, this slightly changed -- the static context is initialized only when the user code interacts with static members of the type.

Related

Overriding static properties in F# with extension methods

F# extension methods can be defined on types with the same name and type signature as existing instance and static methods to effectively override the default implementation of these methods, however I can't get this to work on static properties.
In particular, I'm trying to create an extension method for DateTime that returns a more precise time as follows:
#nowarn "51"
open System
module DateTimeExtensions =
open System.Runtime.InteropServices
[<DllImport("Kernel32.dll", CallingConvention = CallingConvention.Winapi)>]
extern void private GetSystemTimePreciseAsFileTime(int64*)
type System.DateTime with
// example showing that static methods can be overridden
static member IsLeapYear(_: DateTime) =
printfn "Using overridden IsLeapYear!"
true
// more accurate UtcNow method (note: not supported by older OS versions)
static member UtcNow =
printfn "Using overridden UtcNow!"
let mutable fileTime = 0L
GetSystemTimePreciseAsFileTime(&&fileTime)
DateTime.FromFileTimeUtc(fileTime)
However, the output when executing
open DateTimeExtensions
let _ = DateTime.IsLeapYear(DateTime.UtcNow)
is just
Using overridden IsLeapYear!
which shows that the static method 'override' is working, but not the static property.
(Note: I'm using F# 4.0)
This statement seems to be incorrect:
F# extension methods can be defined on types with the same name and
type signature as existing instance and static methods to effectively
override the default implementation of these methods, however I can't
get this to work on static properties.
No, they don't override.
You might be confused because in fact your signature of IsLeapYear is wrong, it should take an integer, that's why it works I mean you are not overriding anything, just adding a new (extension) method.
If you try it with the original signature you'll see that it doesn't work either:
type System.DateTime with
// example showing that static methods can NOT be overridden
static member IsLeapYear(_: int) =
printfn "Using overridden IsLeapYear!"
false
> DateTime.IsLeapYear(2000);;
val it : bool = true
Which is consistent with the behavior of the static property extension.
Anyway I'm not sure why it was decided not to override, if there was such decision at all when designing the language. I think it would be an interesting feature and if there is a good reason not to implement it at least it should emit a warning saying that since the method already exists it will never be called.
Maybe I will open an issue or a suggestion for the F# compiler.

How to convert C# code that uses Shell COM to F#?

I have the following C# method:
private static bool IsLink(string shortcutFilename)
{
var pathOnly = Path.GetDirectoryName(shortcutFilename);
var filenameOnly = Path.GetFileName(shortcutFilename);
var shell = new Shell32.Shell();
var folder = shell.NameSpace(pathOnly);
var folderItem = folder.ParseName(filenameOnly);
return folderItem != null && folderItem.IsLink;
}
I have tried converting this to F# as:
let private isLink filename =
let pathOnly = Path.GetDirectoryName(filename)
let filenameOnly = Path.GetFileName(filename)
let shell = new Shell32.Shell()
let folder = shell.NameSpace(pathOnly)
let folderItem = folder.ParseName(filenameOnly)
folderItem <> null && folderItem.IsLink
It however reports an error for the let shell = new Shell32.Shell() line, saying that new cannot be used on interface types.
Have I just made a silly syntactic mistake, or is there extra work needed to access COM from F#?
I don't know enough about the F# compiler but your comments makes it obvious enough. The C# and VB.NET compilers have a fair amount of explicit support for COM built-in. Note that your statement uses the new operator on an interface type, Shell32.Shell in the interop library looks like this:
[ComImport]
[Guid("286E6F1B-7113-4355-9562-96B7E9D64C54")]
[CoClass(typeof(ShellClass))]
public interface Shell : IShellDispatch6 {}
IShellDispatch6 is the real interface type, you can also see the IShellDispatch through IShellDispatch5 interfaces. That's versioning across the past 20 years at work, COM interface definitions are immutable since changing them almost always causes an undiagnosable hard crash at runtime.
The [CoClass] attribute is the important one for this story, that's what the C# compiler goes looking for you use new on a [ComImport] interface type. Tells it to create the object by creating an instance of Shell32.ShellClass instance and obtain the Shell interface. What the F# compiler doesn't do.
ShellClass is a fake class, it is auto-generated by the type library importer. COM never exposes concrete classes, it uses a hyper-pure interface-based programming paradigm. Objects are always created by an object factory, CoCreateInstance() is the workhorse for that. Itself a convenience function, the real work is done by the universal IClassFactory interface, hyper-pure style. Every COM coclass implements its CreateInstance() method.
The type library importer makes ShellClass look like this:
[ComImport]
[TypeLibType(TypeLibTypeFlags.FCanCreate)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("13709620-C279-11CE-A49E-444553540000")]
public class ShellClass : IShellDispatch6, Shell {
// Methods
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime), DispId(0x60040000)]
public virtual extern void AddToRecent([In, MarshalAs(UnmanagedType.Struct)] object varFile, [In, Optional, MarshalAs(UnmanagedType.BStr)] string bstrCategory);
// Etc, many more methods...
}
Lots of fire and movement, none of it should ever be used. The only thing that really matters is the [Guid] attribute, that provides the CLSID that CoCreateInstance() needs. It also needs the IID, the [Guid] of the interface, provided by the interface declaration.
So the workaround in F# is to create the Shell32.ShellClass object, just like the C# compiler does implicitly. While technically you can keep the reference in a ShellClass variable, you should strongly favor the interface type instead. The COM way, the pure way, it avoids this kind of problem. Ultimately it is the CLR that gets the job done, it recognizes the [ClassInterface] attribute on the ShellClass class declaration in its new operator implementation. The more explicit way in .NET is to use Type.GetTypeFromCLSID() and Activator.CreateInstance(), handy when you only have the Guid of the coclass.

Working with SafeHandles in F#

I'm working with some F# code that uses platform invoke. One of the APIs I'm using returns a handle. Instead of using a nativeint, I've implemented my own SafeHandle (specifically SafeHandleMinusOneIsInvalid.) This makes working with the module containing the pinvoke signature a little clunky. Here is an example:
type MySafeHandle() =
inherit SafeHandleZeroOrMinusOneIsInvalid(true)
override this.ReleaseHandle() =
NativeMethods.FreeHandle(base.handle)
true
module NativeMethods =
[<DllImport("mylibrary.dll")>]
extern void GetHandle([<Out>]MySafeHandle& handle)
[<DllImport("mylibrary.dll")>]
extern void FreeHandle(nativeint handle)
This won't compile because the module and the class recursively reference each other, which doesn't work. If I move the module above MySafeHandle, then GetHandle won't see the SafeHandle.
I can't move the platform invoke methods inside of MySafeHandle since it appears that extern methods in F# must be in modules (even though the compiler won't stop you from trying to put them in a class).
It also appears that F#'s recursive types don't work between a module and a class, just classes.
Is there a solution to this problem that does not require declaring two different modules? Ideally I'd like to keep all of my platform invoke code organized into one module.
Well I know of one, because I had the same problem myself.
The thing is, it's kinda ugly I guess:
It involves a static reference that you set to the imported function later in the module.
type MySafeHandle() =
inherit SafeHandleZeroOrMinusOneIsInvalid(true)
static let freeHandle = ref Unchecked.defaultof<_>
static member internal SetFreeHandleRef value = freeHandle := value
override this.ReleaseHandle() =
!freeHandle base.handle
true
module NativeMethods =
[<DllImport("mylibrary.dll")>]
extern void GetHandle([<Out>]MySafeHandle& handle)
[<DllImport("mylibrary.dll")>]
extern void FreeHandle(nativeint handle)
MySafeHandle.SetFreeHandleRef FreeHandle

Idiomatic constructors in F#

I started with a small OpenGL wrapper and I run into a small problem. I usally create my data with records like this
type Shader =
{ Handle : int }
static member Create filepath stype =
let h = loadshader filepath stype
{ Handle = h }
type VertexShader =
{ shader : Shader }
static member Create path =
{ shader = Shader.Create path ShaderType.VertexShader }
type FragmentShader =
{ shader : Shader }
static member Create path =
{ shader = Shader.Create path ShaderType.FragmentShader }
I am always using a static constructor with a non tupled function. But now I want another type where I would like to have optional parameters.
like
type VAO =
{ Handle : int }
static member Create vboList ?ibo =
........
The problem is that this doesn't seem to be possible with non-tupled functions and I don't want to mix my Create methods with tupled and non-tupled functions.
I wonder if I even wrote idiomatic F# code in the first place. How would you approach this "problem"?
You're right -- if you want to define optional parameters for a method, you need to define the arguments in tupled form. One way you could approach this would be to move the implementation of your Create method into a private method (and rename it, e.g., to CreateImpl), then re-define Create as an overloaded method which will simply dispatch to the implementation. For example:
type VAO =
{ Handle : int }
static member private CreateImpl (vboList, ibo : _ option) =
failwith "Not implemented."
static member Create vboList =
VAO.CreateImpl (vboList, None)
static member Create (vboList, ibo) =
VAO.CreateImpl (vboList, Some ibo)
Another approach, is to define a module (it needs to be placed below the definition of your VAO type) which defines curried functions which "wrap" the static VBO.Create(...) method. This'll work however you decide to declare the arguments for Create (i.e., using a single method with tuple-style argument declaration and optional parameters, or using the overloading approach described above). For example, if you don't use my overloading method, and decide to just define Create as static member Create (vboList, ?ibo):
// The [<CompilationRepresentation>] attribute is necessary here, because it allows us to
// define a module which has the same name as our type without upsetting the compiler.
// It does this by suffixing "Module" to the type name when the assembly is compiled.
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix>]
module VAO =
let create (vboList : _ list) =
VAO.Create vboList
let createWithIndex vboList ibo =
VAO.Create (vboList, ibo)
Those module functions are very simple, so it's very likely they'll be inlined automatically by the F# compiler and you won't pay any run-time costs for them. If you compile in Release mode, inspect the assembly's IL and find that's not the case, then you can add the inline keyword to the function definitions to force them to be inlined. (Best not to do force inlining unless you benchmark and are certain it offers a real performance gain.)
One tip, unrelated to your question about the optional arguments -- consider re-defining at least some of your types as structs rather than F# records. Record types are compiled into classes (i.e., reference types) so you pay the additional indirection cost for no reason; defining them as structs will eliminate this indirection and give your application better performance. Better yet, if you're able to, re-use one of the existing OpenGL wrapper libraries like OpenTK or OpenGL4Net.

F# top level do binding

I have a file with a module with some routines that take parameters and return unit, these routines have side-effects. I noticed that when accessing these f# routines from c# they're actually properties of type unit and when I try to access 1 property, it runs all properties in the module.
From the F# documentation all top level do bindings are run on type initialization.
What is the preferred way to write functions that should not be run on type initialization but are also not associated with other state i.e. a class with functions and member variables?
Should I put these functions inside a type and just have no records in the type?
Code example:
namespace test_space
open System.Diagnostics;
module test =
let test_1 =
Debug.WriteLine ("One")
let test_2 =
Debug.WriteLine ("Two")
I'm running this code with C#:
static void Main (string [] args)
{
Object o;
o = test.test_2;
}
And the output is:
One
Two
The problem is you didn't create functions but value bindings. test_1 is a value. test_1() is a function of type unit -> unit. Make sure you put () after the function name.
I don't fully understand the scenario you're describing - F# functions declared in a module will generally appear as methods and values will appear as properties. The code that is executed when you first access module (type initialization) is the initialization of values.
If you write just:
module Foo =
let Operation () =
printfn "hello"
...then calling Operation will be a method and calling Foo.Operation() will run the side-effect. If you can post some code that behaves unexpectedly, then someone can explain it.
Anyway, if you want to be sure about the behavior, you can write operations as static members of a class:
type Foo =
static member Operation() =
printfn "hello"
Then you can be sure that F# will compile them as static members of a class in a predictable way.

Resources