2

I'm extremely new to F# and was playing around with the stack calculator on the F# for fun and profit (excellent site). I was trying to figure out how to have a test project and class. I have a test class with this method:

open NUnit.Framework
open FSharpDoodles.MainProgram

[<TestFixture>]
type ProgramTests()=

    [<Test>]
    member self.FirstTest()=
        // Create some stacks
        let EMPTY = StackContents []
        let try1 = push 1.0 EMPTY      // OK
        let try2_partial = push 1.0    // OK
        let try2 = try2_partial EMPTY  // OK - does same as ONE below
        let stackWith1 = ONE EMPTY     // FAILS: ONE is null
        ()

The code it is testing is thus:

module FSharpDoodles.MainProgram 

type Stack = StackContents of float list

let push x (StackContents contents) =
    StackContents ( x::contents )

let ONE = push 1.0

So, if I'm calling a function and getting a value (call to push), it works. And if I create a partially applied function in the class (try2_partial), that works. But when I'm referencing ONE, which is returning a partially applied function, ONE is null.

Why is that?

The Rest of The Story

I'm using NCrunch as my test runner. It is entirely possible that it is causing a problem.

Edit

As suggested by John, I tried this in FSI and get the same issue. Below is the progressive application of the same test code:

open FSharpDoodles.MainProgram
let EMPTY = StackContents [];;


val EMPTY : FSharpDoodles.MainProgram.Stack = StackContents []

> let try1 = push 1.0 EMPTY;;


val try1 : Stack = StackContents [1.0]

> let try2_partial = push 1.0;;


val try2_partial : (Stack -> Stack)

> let try2 = try2_partial EMPTY;;


val try2 : Stack = StackContents [1.0]

> let stackWith1 = ONE EMPTY;;
System.NullReferenceException: Object reference not set to an instance of an object.
   at <StartupCode$FSI_0006>.$FSI_0006.main@()
Stopped due to error

I made a reference to the SUT for FSI under Tools|Options -> F# Interactive, F# Interactive options. I used -r and referenced the assembly in debug\bin.

As I mentioned, I very new to this F# stuff and I might be making some very rookie mistake related to how I'm putting together either of the modules.

Update 2

Based on John's comment, I tried moving the code from an .exe to a .dll (library). It worked fine. So, the issue is related to referencing the .exe. So the question now evolves into why this makes a difference (exe vs dll)?

Greg McGuffey
  • 3,116
  • 3
  • 38
  • 58
  • 1
    My guess would be the test runner not calling the module setup correctly, leaving the `ONE` uninitialised. You can test this by running the code in FSI. Maybe try a different test runner? – John Palmer Jul 12 '14 at 07:41
  • That sounds reasonable. I've just executed this test with TestDriven.NET, and it works as expected; stepping through with the debugger shows that both `stackWith1` and `ONE` are proper values (and not null). – Mark Seemann Jul 12 '14 at 14:43
  • What do you get in fsi when you just try to evaluate `ONE`? – Christopher Stevenson Jul 13 '14 at 04:05
  • Are you compiling the assembly containing `ONE` as an exe or a dll? – John Palmer Jul 13 '14 at 05:06
  • As an exe (console app). – Greg McGuffey Jul 14 '14 at 14:14
  • Same error when I try to evaluate ONE: let s = ONE 1.0 StackContents [];; The value or constructor 'ONE' is not defined – Greg McGuffey Jul 14 '14 at 14:14
  • 1
    OK, this is related to it being an EXE. I moved code to a library and it worked fine. Thanks to John for asking the right question. :D If somebody knows why this makes a difference (exe vs dll) or has a link to a reference about this, post it as the answer. – Greg McGuffey Jul 18 '14 at 23:38
  • Perhaps this covers it? http://stackoverflow.com/a/6630262/82959 – kvb Jul 21 '14 at 18:36
  • 1
    Didn't see the comment replies earlier but the difference is that when the code is compiled as an exe, F#, inserts some initialization code that runs early. When you reference the exe, this code doesn't run. Compiling as a dll fixes this. – John Palmer Jul 21 '14 at 22:03

1 Answers1

0

The reason it didn't work is that I was referencing an EXE and not a DLL. Same code in a DLL works fine. Thanks to John Palmer question for getting me to investigate that angle and then for providing the explanation (see the comments).

Community
  • 1
  • 1
Greg McGuffey
  • 3,116
  • 3
  • 38
  • 58