Cannot test for exceptions in F# using xUnit - f#

Here is the code:
module Tests
open System
open Xunit
[<Fact>]
let ``Simple Test`` () =
Assert.Throws<Exception>(failwith "Error")
This fails to compile with:
error FS0041: A unique overload for method 'Throws' could not be determined based on type information prior to this program point. A type annotation may be needed. Known type of argument: 'a Candidates: - Assert.Throws<'T when 'T :> exn>(testCode: Action) : 'T - Assert.Throws<'T when 'T :> exn>(testCode: Func<Threading.Tasks.Task>) : 'T - Assert.Throws<'T when 'T :> exn>(testCode: Func<obj>) : 'T
What am I doing wrong?

Its looking for an Action or a Func, you CAN use a F# lambda and the compiler will implicitly create a Func for you.
module Tests
open System
open Xunit
[<Fact>]
let ``My test`` () =
Assert.Throws<Exception>(
fun () ->
(failwith "Error") :> obj)
you have to cast the output in this example to tell compiler what the return type of the function is (it could be anything, as it returns nothing)

Related

Code breaks when moving recursive types around

During refactoring of some code, I noticed a situation where code breaks when moved around:
type ThingBase () = class end
and Functions =
static member Create<'T when 'T :> ThingBase and 'T : (new : Unit -> 'T)> () = new 'T ()
and Thing () =
inherit ThingBase ()
static member Create () = Functions.Create<Thing> ()
// This works, but try moving the Functions type here instead.
If you move the Functions type below the Thing type, the code breaks unexpectedly:
type ThingBase () = class end
and Thing () =
inherit ThingBase ()
static member Create () = Functions.Create<Thing> ()
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
// This construct causes code to be less generic than indicated by the
// type annotations. The type variable 'T has been constrained to be
// type 'Thing'.
and Functions =
static member Create<'T when 'T :> ThingBase and 'T : (new : Unit -> 'T)> () = new 'T ()
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// The type ''T' does not match the type 'Thing'.
And no matter what I try, I cannot get this to typecheck. Why is the type inference so stubborn and refusing to generalize the Create method.
By the way, I also attempted F# 4.1 module rec and it also doesn't matter if Create is a function in a module either.
Any insights? To me it seems this should be something the compiler shouldn't have any troubles with.
It will compile if you do this
static member Create<'T when 'T :> ThingBase
and 'T : (new : Unit -> 'T)> () : 'T = new 'T ()
// ^^^^
where the return type is explicitly stated.
Recursive definitions are typechecked left-to-right in two passes; first function/method signatures, then bodies. You need the body (or an explicit return type annotation) to get the result type, so you either need the body to come first, or else the annotation so that it gets solved in the first of the two passes.
I have no idea why the compiler over-constrains the type parameter of the Create method when you move it up. A work-around could be an intrinsic type extension, so you can split the type definition into multiple sections. Which can help to avoid recursive dependencies.
type ThingBase () = class end
type Thing () =
inherit ThingBase ()
type Functions =
static member Create<'T when 'T :> ThingBase and 'T : (new : Unit -> 'T)> () =
new 'T ()
type Thing with
static member Create () = Functions.Create<Thing> ()
If you want to keep moving forward with that pattern, here's how to do it. I'm assuming you want some kind of factory pattern embedded in the base.
Incidentally, when #Fyodor says left-to-right, this also means top-down. So... you may be fighting against this, too, even though the and functionality should logically, be working. I also agree re: flatter hierarchies, but sometimes, we don't get to have the luxury of choice for various reasons.
type ThingBase () = class end
and Thing () =
inherit ThingBase ()
and Functions() =
static member Create<'T when 'T :> ThingBase and 'T : (new : Unit -> 'T)> () = new 'T ()
and Thing with
static member Create () = Functions.Create<Thing> ()
// typically, I'd prefer
//type Thing with
// static member Create () = Functions.Create<Thing> ()
// or
//module Thing =
// let Create() = Functions.Create<Thing> ()
references:
https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/type-extensions
The below is incorrect. Apparently recursive definitions get two passes of type checking - once for signatures, then for implementations. I'm leaving the answer here anyway, just for reference.
Original answer
Type inference works left to right, in one pass. Once it encountered a call to Functions.Create, it has decided what the signature has to be, and later augmentations can't change that.
It's the same reason that xs |> Seq.map (fun x -> x.Foo) works, but Seq.map (fun x -> x.Foo) xs doesn't: in the first instance the type of x is known from the previous encounter of xs, and in the second instance it's not known, because xs hasn't been encountered yet.
P. S. You don't actually need a recursive group there. There are no recursive dependencies between your types.

Why is Type Annotation Required Here?

This function has the signature: (UnionCaseInfo -> bool) -> 'T option
let private findCase<'T> f =
match FSharpType.GetUnionCases typeof<'T> |> Array.filter f with
|[|case|] -> Some (FSharpValue.MakeUnion(case,[||]) :?> 'T)
|_ -> None
This function, which calls the above function, has the signature: int -> obj
let CreateFromId<'T> id =
match findCase (fun case -> case.Tag = id) with
| Some c -> c
| None -> failwith (sprintf "Lookup for union case by \"%d\" failed." id)
In the pattern for CreateFromId, intellisense shows that c is inferred to be of type obj, even though it shows the correct signature for findCase. Why does the type seem to have been "lost" in the pattern?
(I can workaround this by specifying the return type of CreateFromId to 'T)
Because the type parameter 'T is not referenced in the body of the function, so type inference has no way to know your intention was to name 'T the return type.
So you can either add it in the body as the return type (as you already figured it out) or remove it from the declaration:
let CreateFromId id = ...
By removing it works because F# does automatic generalization, the only different is it will use an arbitrary name for the type variable, but even if you want to name that type variable 'T what I would do is add it as a return type but no in the declaration between brackets:
let CreateFromId id : 'T = ...
The type of CreateFromId was inferred to by int -> obj because there's nothing "linking" the two 'T type arguments on your functions.
findCase is properly generic over 'T, but CreateFromId is only declared to be generic, and the generic type argument is never used.
Annotating the function with the desired type is good enough to make the types line up. You can also call findCase explicitly providing the type:
let CreateFromId<'T> id =
match findCase<'T> (fun case -> case.Tag = id) with
| Some c -> c
| None -> failwith (sprintf "Lookup for union case by \"%d\" failed." id)
Or as the other answer suggests, just drop the 'T from CreateFromId and let type inference do its thing.

Generic function definition as type in F# signature file

I can define a generic signature type and define a function which implements that signature:
[<Measure>] type ms
type timer<'a,'b> = ('a -> 'b) -> 'a -> 'b * int64<ms>;;
let timeit:timer<'a,'b> = fun f x -> ((f x), 1L<ms>);;
I can also put that type definition in an F# signature file (.fsi).
module Utils =
type timer<'a,'b> = ('a -> 'b) -> 'a -> 'b * int64<ms>
But when I try to use that type definition in the implementation file, the compiler says 'The type "timer" is not defined'.
[<Measure>] type ms
module Utils =
let timeit:timer<'a,'b> = fun f x -> ((f x), 1L<ms>);;
Is this the expected behavior?
You need to declare your timer<_, _> type in the .fs file too.
Basically, the signature file is a convenience to document the public API of the source file, but it doesn't by itself declare anything that can be used in the source file. If this is not something you need, you can just drop the signature file and only use a source file.

Generic type constrained on f# method involving static type conversion

I'm trying to create a function in FSharp that will take a parameter of an interface type and a parameter of a derived type, which passes on both parameters as implementations of that interface:
Simplified example:
type IFoo =
abstract member Compare : IFoo -> bool
type Foo =
interface IFoo with
member this.Compare _ = false
let doCompare (a : IFoo) (b : IFoo) = a.Compare(b)
let comp (x : IFoo) (y : #IFoo) = doCompare x (y :> IFoo)
let comp2 (x : 'T) (y : #'T) = doCompare x (y :> 'T)
I'm getting the following two errors on the generic version (here, comp2):
On the parameter:
This construct causes code to be less generic than indicated by its type annotations.
The type variable implied by the use of a '#', '_' or other type annotation at or near '...'
has been constrained to be type ''T'.
On the cast operator:
The static coercion from type 'T to 'T involves an indeterminate type based on information prior to this program point.
Static coercions are not allowed on some types. Further type annotations are needed.
Is there a way I can fix this, other than creating a signature using 'T 'U and casting via object which is obviously unsafe ?
This code (together with the original code that showed this problem - which is for wrapping NSubstitute in a test fixture) is available on tryfsharp
The # is syntactic sugar for a subtype constraint, ie. comp2 is equivalent to:
let comp2<'T, 'U when 'U :> 'T> (x:'T) (y:'U) = doCompare x (y :> 'T)
Unfortunately, the 'U :> 'T part is not supported by the type system (you cannot constrain a type to be a subtype of a type variable), so this is not possible.

How to define and use % as a prefix operator?

type T() =
static member (~%)(t : T) = t
let t = T()
let t' = %t // FAILS
The error message says t was expected to be of type Quotation.Expr<'a>.
% is a supposedly valid prefix operator, but is it possible to actually use it?
The reason why you are seeing this behavior is because F# does not define (~%) with static constraints like most top-level operators. It is defined as a function Quotations.Expr<'a> -> 'a. Hence, the (~%) function (which is an alias for op_Splice) you defined on type T is not resolved by uses of the top-level (~%) operator.
You can see this by the following FSI interaction:
> <# (~%) #>;;
<# (~%) #>;;
^^^^^^^^^^
C:\Users\Stephen\AppData\Local\Temp\stdin(5,1): error FS0030: Value restriction. The value 'it' has been inferred to have generic type
val it : Expr<(Expr<'_a> -> '_a)>
Either define 'it' 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.
Thus if we redefine the top-level (~%) operator as follows, then your example will compile without error:
let inline (~%) (x : ^a) = (^a : (static member op_Splice : ^a -> 'b) (x))
but do note that quotation splicing will no longer work:
let x = <# 3 #>
<# %x #>
----^
error FS0001: The type 'Expr<int>' does not support the operator '~%'
that's because the original definition of (~%) is treated specially by the compiler for quotation splicing. Indeed, you can see in the Expr and Expr<'T> signatures that those types do not define any operators at all, let alone op_Splice.
You can see similar results with && and || infix operators. Which can be redefined (mapping to op_BooleanAnd and op_BooleanOr), but unless they are, they are treated specially by the compiler.
I'm not exactly sure why the % operator behaves like this, but you can redefine it using global let binding:
let (~%) a = -a
%10
If the operator cannot be defined as static member (I'm not sure if that's the case, or if I'm just missing something), you can still define an inline definition that invokes some static member of an object. This should give you essentially the same functionality:
// Instead of defining static member '%', we define static member 'Percent'
type T() =
static member Percent(t : T) = t
// Inline definition of '~%' that calls the static member 'Percent' of an object
let inline (~%) (x : ^T) = (^T : (static member Percent : ^T -> 'R) (x))
// Now you can use the '%t' syntax to invoke the static member
let t = T()
let t' = %t
Background: In F# quotation code, it is used for "splicing" of expressions into another expression (to build an expression that is composed from another, previously defined expression). The error message suggests that the compiler did not see your definition.
let two = <# 2 #>
let oneAndTwo = <# 1 + %two #>

Resources