F# NUnit test sets value as null - f#

I have 2 files: Asm.fs, AsmTest.fs
Asm.fs
namespace Assembler
[<Measure>] type ln
[<Measure>] type col
[<Measure>] type port
type Addr = int<ln> * int<col> * int<port>
module Asm =
let emptyAddr : Addr = (-1<ln>, -1<col>, -1<port>)
AsmTest.fs
module Assembler.Tests
[<Test>]
let someTest() =
let x = Asm.emptyAddr
When I debug someTest() code, I get that x = null, what am I doing wrong?
P.S. files in the different projects visual studio projects. Asm.fs in the Assembler project and AsmTest.fs in the AssemblerTest project.
I found an interesting behavior. My problem will be resolved, if I add some file (even empty) to the Assembler project. Can anyone explain this behavior?

The debugger sometimes has issues showing the correct values. For me however, having exactly the same Asm.fs and AsmTest.fs like this:
module Assembler.Tests
open NUnit.Framework
[<Test>]
let someTest() =
let x = Asm.emptyAddr
Assert.IsNotNull x
the test passes and if I set a breakpoint at the assertion, x is correctly shown as {(-1, -1, -1)}
As the code that you show does not compile as it is (Block following this let is unfinished. in someTest), could you try my test above and/or show your complete test method?
Using your code I can reproduce the behaviour. If I set my projects to console applications, my test will fail as well. So, it seems that for console projects, not having any other file or an [<EntryPoint>] surprisingly skips the initialization of module values. For me, the compiler at least issues a warning Main module of program is empty where I use x in the test. The solution to the problem is therefore:
make sure you treat warnings as errors
have an [<EntryPoint>] for console applications
use library projects for libraries

Related

Using and installing MathNet Package

I have installed the MathNet.Numerics package on Visual Studio 2017 using the Package Manager Console.
I have attempted to open a Source File on and execute an algorithm relating to the MersenneTwister type within the MathNet namespace.
However, when I try to generate numbers using this algorithm in F# Interactive, I am met with the error:
File1.fs(3,6): error FS0039: The namespace or module 'MathNet' is not defined. Maybe you want one of the following:
Math
Code is as per below:
module File1
open MathNet.Numerics.Random
let mersenneTwister = new MersenneTwister(42)
let a = mersenneTwister.NextDouble()
Apologies if this is unclear, I am relatively new to F# :)
Are you per change using the interactive window or running an fsx script? Cause these don't recognize your packages.
When reproducing your problem in a F# console app I got this output: Hello 0.374540.
I installed the MathNet.Numerics.fsharp nuget package (which also uses the package you mention) and used the following code in the Program.fs:
open MathNet.Numerics.Random
let hello () =
let mersenneTwister = new MersenneTwister(42)
let a = mersenneTwister.NextDouble()
printfn "Hello %f" a
[<EntryPoint>]
let main argv =
hello ()
0 // return an integer exit code
If you do want to use the nuget package from a script you can reference it in the top of your script like so (absolute or relative)
#r #"C:\Path\bin\Debug\netcoreapp3.0\MathNet.Numerics.dll"

F# interactive Marshal.SizeOf with Mono throws “assertion” error

I am trying to read a GIF file header into a structure with F#, using Mono 5.8 on Mac OSX. The following code sample works fine in Visual Studio 2017 on Windows 10; however, when I try to run it in Visual Studio for Mac, I get the following error in F# interactive:
* Assertion at class-accessors.c:138, condition `mono_class_has_static_metadata (klass)' not met
The code I am using is below. The structure is probably incorrect since I just threw it together quickly for the question, but
open System
open System.IO
open System.Runtime.InteropServices
[<Struct; StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)>]
type GifHeader = {
[<MarshalAs(UnmanagedType.ByValTStr, SizeConst = 3)>]
signature: string
[<MarshalAs(UnmanagedType.ByValTStr, SizeConst = 3)>]
version: string
logicalWidth: int16
logicalHeight: int16
}
When I invoke Marshal.SizeOf(typeof<GifHeader>) in Visual Studio for Mac's FSI, I get the error mentioned above.
I noticed that when I am reading into a structure like:
[<Struct; StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)>]
type SomeOtherHeader = {
field1: uint16
field2: int32
field3: int16
field4: float
}
i.e. with no MarshalAs UnmanagedType specification, the error is not thrown.
Does anyone know what this error means? I haven't seen any other instances of this particular error on Google or other SE posts, and it is especially puzzling since it doesn't occur on Windows/.NET Framework 4.7. Not having the interactive window to test code is a massive hindrance for learning, and quite frustrating since I don't think it's possible to use an alternative (non-Mono) FSI.
This was an issue intrinsic to the current Mono release. Per the Mono team, this has been fixed as of Mono 5.14.

F# function changes type when compiled with standalone switch and referenced from another project

In a Visual Studio project for an F# library I have defined a function as
let inline Estimate (s : ^a seq) (f : float) (w : int) : float * float = ..
The type of Estimate is
val Estimate : s:seq<'a> -> f:float -> w:int -> float*float
Calling Estimate from a script within that project works as expected.
Now if I compile the project with the --standalone switch and reference the output DLL from another project, Estimate is shown to be
Estimate<'a,'a>(s: Collections.Generic.IEnumerabls<'a>, f: float, w:int) : float*float
i.e. it some reason now takes tuple arguments.
Thus the following does not work
let q, p = EstimationQuality.Estimate x f 1 // This value is not a function and cannot be applied
but calling it with tuple parameters works fine
let q, p = EstimationQuality.Estimate (x, f, 1) // No problem.
What's wrong here? Is it a bug in the compiler?
EDIT:
Digging a little deeper, it appears that the problem is linked with the use of LanguagePrimitives.GenericZero.
While the problem actually compiles with the tuple parameter call, i get a runtime error when Estimate is called.
An unhandled exception of type 'System.TypeInitializationException'
occurred in LibraryTest.dll
Additional information: The type initializer for
'GenericZeroDynamicImplTable`1' threw an exception.
Compiling an F# DLL which is intended to be used from F#, with the standalone switch is not a good idea.
Why? Because all the F# metadata is lost since the whole set of F# types are included in your DLL so those types get a different identity from the types of the F# application that call your DLL or fsi.
The caller assembly uses the types in Fsharp.Core.dll which now are not the same as the ones used in your standalone compiled DLL.
That's why you see the tupled arguments, as seen from C# which doesn't understand F# metadata at all.
Generic inline functions using static constraints break as well since they need the metadata to inline at the call site.
Compiling also the caller assembly as standalone would make things worse, then you will have 3 sets of Fsharp types with different identities.
I think the standalone switch is fine when used only in the 'end-user' application.

Compile with standalone flag gives compilation errors in client code

I'm attempting to compile Zero29 with the --standalone compiler flag. The project itself compiles fine, but I have a unit test project that exercises some code in the Zero29 project, even though it's an executable program (.exe).
Everything works fine without the --standalone compilation flag.
However, when I add the --standalone compilation flag to the Zero29 project, the Zero29 project compiles fine, but in the unit test project, the compiler complains about this Discriminated Union defined in the Zero29 project:
namespace Ploeh.ZeroToNine
open System
open Ploeh.ZeroToNine.Versioning
type Arg =
| Assign of Version
| AssignRank of Rank * int
| Increment of Rank
| ListVersions
| ShowHelp
| Unknown of string list
The unit test project directly references the Zero29 project:
Zero29.UnitTests --references--> Zero29 (where --standalone is added)
When I attempt to compile the entire solution, the Zero29 project compiles with the --standalone flag, but then compilation of Zero29.UnitTests fails. There are several errors, but they are all the same, so here's a single example:
error FS0039: The value or constructor 'Assign' is not defined
Which points to the third line of this code:
let ParseAssignVersionReturnsCorrectResult(version : string) =
let actual = [| "-a"; version |] |> Args.Parse
verify <# [Assign(Version version)] = (actual |> Seq.toList) #>
The strange thing is that while the compiler complains about Assign in the third line of this code snippet, it doesn't complain about the use of Args.Parse, even though it's defined in the same code file as the Arg Discriminated Union.
Why does it do that, and how can I resolve this issue?
(I've attempted to distil the problem here, but the links I've provided point to the actual code files on GitHub, if more information is required.)
Libraries compiled with the --standalone switch cannot expose any F# datatypes. This is, for one, expressly stated in Pickering (2007), p. 210. In your case, a discriminated union is one of these prohibited types. The fact that the file is an executable changes nothing here: it becomes a library the moment you attempt to use it as one.
There have been also multiple reports (for example, here and here) that even libraries compiled with --standalone behave, quoting one of these sources, “funky.” It would be safe to say that the use of this switch should perhaps be limited to stand-alone executables only (and they cannot pretend to be a library even when under unit tests).
Pickering R. (2007). Foundations of F#. Apress.

Using F# JsonProvider within a portable class library fails

I'm trying to use the JsonProvider and I'm getting the following error when I call a function on it:
System.TypeInitializationException was unhandled
Message: An unhandled exception of type 'System.TypeInitializationException' occurred in PortableLibrary1.dll
Additional information: The type initializer for '<StartupCode$PortableLibrary1>.$PortableLibrary1' threw an exception.
I have a basic console application as follows:
module Pinit =
open FSharp.Data
type JsonT = JsonProvider<"""..\myFile.json""">
let doc = JsonT.Load("""..\nyFile.json""")
let result = doc.GeneratedAt
[<EntryPoint>]
let main argv =
printfn "%A" Pinit.doc.GeneratedAt
0
When run within the ConsoleApplication it all works as expected.
If I create an F# Portable Class library as follows:
module Pinit =
open FSharp.Data
type JsonT = JsonProvider<"""..\myFile.json""">
let doc = JsonT.Load("""..\nyFile.json""")
let result = doc.GeneratedAt
Create another Console Application and reference that Portable Class Library and call the code as follows:
open PortableLibrary1
[<EntryPoint>]
let main argv =
printfn "%A" Pinit.result
0
When I run the program then it generates the exception defined above:
I'm suspecting it's because of the versions of FSharp.Core but was wondering whether I was doing something wrong or whether there was a way to get this to work?
Versions:
-- ConsoleApplication --
FSharp.Core = 4.3.1.0
-- PortableClassLibrary --
FSharp.Core = 3.3.1.0
FSharp.Data = NuGet Version: 2.0.0
let bindings are compiled into static members, and in .NET when you have an exception in a static initializer the real exception is masqueraded.
If you turn that into a function call by changing to let result() = doc.GeneratedAt and printfn "%A" (Pinit.result()) you'll get the real exception:
Only web locations are supported
Portable profiles don't support accessing the file system. So inside the PCL you can either have web urls or load manually from an embedded resource. See here for an example: https://github.com/ovatsus/Apps/blob/master/Trains/Stations.fs#L65. Or you can load the file with File.ReadAllText in the console project and pass it to the PCL.
This was with a Portable Profile (Legacy) project, which is Profile 47 (and FSharp.Core 2.3.6.0). I then also tested with a Portable Profile project, which is Profile 7 (and FSharp.Core 3.3), and noticed it's not working correctly, it's giving this exception instead
Method not found: 'FSharp.Data.Runtime.JsonValueOptionAndPath FSharp.Data.Runtime.JsonRuntime.TryGetPropertyUnpackedWithPath(FSharp.Data.Runtime.IJsonDocument, System.String)'.
I created a github issue to track that: https://github.com/fsharp/FSharp.Data/issues/521

Resources