13

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.)

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • This looks like a bug in the F# Compiler (fsc.exe) since the build arguments are exactly the same when the Zero29 project is compiled with and without the `--standalone` compiler flag. – Nikos Baxevanis Mar 23 '14 at 21:56
  • 1
    I can't say that the thought didn't cross my mind, by I always hesitate to say that *Select is Broken*... – Mark Seemann Mar 24 '14 at 06:22
  • It seems that in the case Zero29 is compiled with the `--standalone` flag, Args.Assign and friends appear as "Nested types". When Zero29 is compiled without the `--standalone` flag, "Assign" becomes a "Union case Args.Assign". It seems the compiler is omitting something in the standalone case. A possible next step is to look at the generated types. Some relevant discussion seems to be here: http://stackoverflow.com/questions/17832203/is-f-aware-of-its-discriminated-unions-compiled-forms – jpe Nov 07 '14 at 15:52

1 Answers1

6

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.

Community
  • 1
  • 1