4

Sorry for the vague description, couldn't find a better way to plain it.

I'm starting with F# and like many others I'm translating my solved Euler problems to F#. I like to run my code using tests and also I like the FsUnit style. With the help of the given example I did this:

open System
open NUnit.Framework
open FsUnit

type EulerProblem() =
    member this.problem1 = Seq.init 999 (fun n -> n + 1)
                             |> Seq.filter (fun n -> n % 3 = 0 || n % 5 = 0)
                             |> Seq.sum

[<TestFixture>]
type ``Given an Euler problem`` () =
    let euler = new EulerProblem()

    [<Test>] member test.
        ``when I try to solve #1 should return [the magic number]`` ()=           
            euler.problem1 |> should equal [the magic number]

This works, but I cannot understand what the period after the test method does. If I take it away the compiler complaints saying:

This instance member needs a parameter to represent the object being invoked. Make the member static or use the notation 'member x.Member(args)

Sorry if this is trivial, and maybe i'm not using the correct wording but couldn't get an answer with google.

Thanks

Marcote
  • 2,977
  • 1
  • 25
  • 24

2 Answers2

4

If you are familiar with C#, or Java, or C++, you can refer to a class instance using the this reserved word within instance members. In F#, you must explicitly give a name to the class instance for each member definition and in the FsUnit example, the name given is merely test but it's not actually used. You could just the same have written the test method as

[<Test>] member this.
    ``when I try to solve #1 should return [the magic number]`` ()=           
        euler.problem1 |> should equal [the magic number]

But note that these days, both xUnit.net and NUnit allow applying their [<Fact>] and [<Test>] attributes respectively for marking tests on let bound functions within modules and without needing TestFixtures and such, which is much better suited for F#. So, for example, the test you gave can and in my opinion ought to be written as:

module EulerProblemTests () =
    [<Test>]
    let ``when I try to solve #1 should return [the magic number]`` () =           
        let euler = new EulerProblem()  
        euler.problem1 |> should equal [the magic number]

Moreover, you probably don't want to create your problem solutions as members of a type like EulerProblem, rather as functions within a module.

Stephen Swensen
  • 22,107
  • 9
  • 81
  • 136
  • Great. Now I have this question: Why F# requires a name to the class instance? Is this to avoid collisions of some kind? I changed the code to use modules, and effectively looks much more readeable. – Marcote Apr 04 '11 at 03:23
  • 1
    Incidentally, this question has recently been asked, see answers and discussion from http://stackoverflow.com/questions/5355334/what-are-the-benefits-of-such-flexible-self-identifiers-in-f for insight. – Stephen Swensen Apr 04 '11 at 03:26
  • Also, I'm glad you found using modules more readable. You may also find my own F# unit testing library more usable in that and other regards: http://code.google.com/p/unquote/ (sorry for the self plug :)). I'm personally off-put by FsUnit because you lose strict static type checking, a hallmark of F# and the ML family. – Stephen Swensen Apr 04 '11 at 03:30
  • Yeah, I just saw it in your profile I'll definitely give a try :), thanks! (BTW, I have two words for you: NuGet Package ;)) – Marcote Apr 04 '11 at 03:36
  • @Markust - I finally got a NuGet package together for Unquote: http://www.nuget.org/List/Packages/Unquote (I hand't heard of NuGet until you mentioned it here, it's great, thanks!). – Stephen Swensen Jun 01 '11 at 19:51
2

It's still a Class, so each member has to be static, or have a "this" defined.

In your test "test" is the "this" for the member.

Normally the class would look like this:

type ClassName() =
    member thisname.MethodName() =
        DoSomeStuff |> DoMoreStuff

With the period, the word "test" was being used, without it it doesn't know what kind of member it is.

Rangoric
  • 2,739
  • 1
  • 18
  • 18