I'm trying to re-write a tiny C# lib in F# and I've encountered an error. I'm trying to define optional parameters for a method in a module but the compiler says "Optional arguments are only permitted on type members".
I've checked why you can't use them in loose functions but when typing static member or member I get another error instead.
module Kingdom =
let Rule (?years : int) =
()
I thought this was going to wor kas it's how I understood you type it, after reading the Microsoft Docs article about it.
By using another way to define the "static class" you can add member to it. And then you can use optional parameters. The class will show up as a normal static class in C#.
[<AbstractClass; Sealed>]
type Kingdom private () =
static member Rule (?years : int) = ()
Related
We know that in C# we can get type of a type at compile time using typeof(OutType) this lets us pass this to attributes later as it is constant expression.
I saw this question, but it doesn't really address the compile time usage.
So my question is: Is there a way to get System.Type of a given module at compile type within F# standard library?
F# disallows obtaining a module's type using its typeof operator by design, as they're not first-class concepts in the language.
From the spec, section 13.2:
F# modules are compiled to provide a corresponding compiled CLI type declaration and
System.Type object, although the System.Type object is not accessible by using the typeof
operator.
Modules compile to static classes however, so it is possible to obtain the type at runtime using reflection (and that's what happens in typeof<MyModule.Dummy>.DeclaringType example), and it's possible to obtain the type of a module defined in a referenced F# assembly using typeofoperator in C#.
For what you're trying to do, you'd best use a class instead of a module, because then you can get hold of the type without hassle:
type MyFactoryClass =
static member TestCases = [ 1; 2; 3 ]
...
[<Test; TestCaseSource(typeof<MyFactoryClass>, "TestCases">]
let test (arg: int) = ...
If you are OK to refer to a type inside that module (or create a dummy one if there are no types), you could do this:
module MyModule =
type Dummy = Dummy
let myModule = typeof<MyModule.Dummy>.DeclaringType
I have an interface which takes a generic parameter and has an abstract method
type MyInterface<'a> =
abstract member abstractMethod: 'a -> 'a
...and I have a derived class which inherits from base class using unit for the type parameter
type Derived() =
interface MyInterface<unit> with
override this.abstractMethod (_) = ()
but the compiler complains that
Error The member 'abstractMethod : unit -> unit' does not have the
correct type to override the corresponding abstract method.
If I use another type instead of unit, int for example, the code compiles.
Is this a bug in the compiler? Is there a workaround for it?
Thanks!
unit is "special" in terms of interop: when a function takes a unit as parameter, it is compiled to IL as a parameterless function, and when a function returns a unit as result, it is compiled as a void function. As a result of this trickery, you can't really use unit as a "general-purpose" type in interop settings (such as classes and interfaces).
In fact, when I try to compile your code on my machine, I get a different error:
The member 'abstractMethod : unit -> unit' is specialized with 'unit'
but 'unit' can't be used as return type of an abstract method
parameterized on return type.
Which is trying to say roughly what I described above.
(I'm not sure why you're getting what you're getting; perhaps you're using an older version of F#)
I have an F# class that uses the following to declare, but not initialize class members:
[<DefaultValue>] val mutable myVariable : myType
How can I check in the code whether this value has been initialized? I tried:
x.myVariable = null
but that doesn't seem to work.
From your description, it is a bit hard to say what you are actually trying to achieve - using both uninitialized values and inheritance is generally not the preferred way of doing things in F# (but they are both sometimes necessary for interoperability with .NET), so if you follow this direction, you might not be getting that many advantages from using F#.
Wouldn't the following work for you instead? The idea is that we define a base class that takes the value of the private thing through a constructor:
type Base(myThing : Random) =
member x.MyThing = myThing
And an inherited class can then provide a value, but also access it using a member:
type MySubclass() =
inherit Base(new Random(0))
member x.Next() =
x.MyThing.Next()
I'm trying to see if inline can be applied to an implemented method so that the specific type coming in doesn't have to be spelled out. I've done this with one off (Not inherited/implemented) methods, but trying to also do using an interface.
type public IBookInteraction =
abstract inline CreateBook : 'a -> MethodResult<BasicBookModel>
type public BookInteraction(?userInteraction) =
interface IBookInteraction with
member inline x.CreateBook(bookModel) =
let userId = (^a : (member UserId : Int32 with get) (bookModel))
MethodResult<BasicBookModel>()
I'm guessing there's a way to do this, but it doesn't work with a generic operator(?) in the interface method signature.
I don't believe it's possible to have abstract inline methods. Even if you could, your code wouldn't work, because your interface definition promises that users can call it with any 'a, but your implementation places a static member constraint on 'a - in a hypothetical world where F# supported abstract inline methods, the declaration of the method on the interface would also need to include the constraint.
In any case, to see why it's not possible for F# to support abstract inline methods, consider what inline means: the code that you write to implement the method will be essentially copied and pasted into the call site. However, with an abstract method, you don't know the concrete type that is defining the implementation of the method, so there's no way to figure out at compile time what code you're supposed to be inlining!
I think the correct answer is interface implementations may not be inlined. I'm not sure why it's allowed in the interface definition.
I know I must be missing something really obvious here. B.GetInstance().Call() generates the error: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.
I'm using v1.9.9.9.
type A() =
member x.Call() = B.GetInstance().Call()
and B() =
static member GetInstance() = new B()
member x.Call() = ()
I just discovered that this works: (B.GetInstance() :> B).Call()
Any idea why the cast is necessary?
Frequently when you've got a recursive set of methods whose types to infer, F# needs help. A more pleasant alternative would be to annotate the definition of B.GetInstance:
type A() =
member x.Call() = B.GetInstance().Call()
and B() =
static member GetInstance() : B = new B()
member x.Call() = ()
I believe that the reason you run into this problem is that F# tries to solve all inferred types on all methods in A and B simultaneously (because they are defined as mutually recursive types), and this leads to problems, but perhaps someone from the F# team will weigh in.
The quick summary is that in a recursive group (e.g. members in one type, or members of recursive types like we have here) F# reads the declarations in left-to-right top-to-bottom order, followed by the definitions in left-to-right top-to-bottom order. So in this instance when it reaches the definition of A.Call, it has not yet read the definition of B.GetInstance and therefore does not (yet!) know that the return type of GetInstance will be B.
Keith's answer nails it for this situation, you can provide a type annotation to specify the return type of GetInstance in its declaration.
See
Forcing F# type inference on generics and interfaces to stay loose
for a deep discussion of what's going on here.
Note also that in your original attempt, you don't need to "cast" (the potentially dynamic operation, using :>), instead you can just "annotate" (statically declare a type, using :) to get it to compile. But makes more sense to put the type annotation in the method declaration for GetInstance (generally, prefer addition annotations to method signatures instead of arbitrary places inside bodies).