ChrisMarinos/FSharpKoans

AssertEquality has confusing behaviors

Closed this issue · 7 comments

Partially due to NUnit, AssertEquality has some behaviors that don't communicate F#'s concept of equality very well. For eample, AssertEquality 2 2.0 will pass which is not consistent with F# equality (2 = 2.0 is a compiler error). Furthermore, these deviations from F# equality aren't even consistent: AssertEquality (2.0, 4.0) (2, 4) fails since NUnit doesn't know how to compare tuples to do the float/int magic.

I think the answer is to remove the dependency on NUnit for comparison, and define a more F#-ey version of AssertEquality. This would probably require a re-visit of every koan. In particular, equality comparison of collections like arrays and lists would need to be implemented. One benefit of removing the Nunit dependency is that it would make it easier to run the koans on the web (eg. in TryF#).

Yes. In addition to equality problems there are output formatting problems with the responses from NUnit. In the lab meeting at NashDotNet several folks did this:

    [<Koan>]
    let TheTruthBehindMultipleReturnValues() =
        let squareAndCube x =
            (x ** 2.0, x ** 3.0)

        let result = squareAndCube 3.0

        AssertEquality result (9,27)

...and were confused by this response:

  Expected: <(9, 27)>
  But was:  <(9, 27)>

Several assumed this was some F# spookiness they would never understand. They were relieved when they learned it was a Koan/NUnit problem.

Yeah, I get some of the most questions about that koan. The test runner should be changed as this issue describes, but I haven't changed the koan itself because it leads to good discussion and learning when I guide groups through the koans.

Firstly thank you for the time and effort put into these koans; Phil Trelford suggested I look here when I asked about learning F#.

I ended up on this very page as I have hit this very snag with the assert on the tuple. For now I've just done the following to pass the test/koan, but try to keep with the spirit of that koan in understanding the tuple return type: -

    //AssertEquality result  (9, 27) Hmm can't seem to get this to work, but...

    AssertEquality 9 (fst result)
    AssertEquality 27 (snd result)

Hopefully this helps someone else hitting the same snag.

The problem has to do with the way AssertEquality defines the idea of being equal. More specifically, it has to do with NUnit's equality semantics, since that's what AssertEquality calls under the hood.

NUnit equality is different than F# equality. For example, 1 does not equal 1.0 in F# (because one is an int and one is a float). However, the NUnit comparer knows how to compare ints and floats, so it would say that they are equal and pass the koan. Unfortunately, NUnit does NOT know how to compare F# Tuples, so it reverts back to the tuple's idea of equality which says that a tuple of int_int does NOT equal a tuple of float_float. That's why your first example fails, but your correction passes.

The way to fix this in the koans would be to write a custom version of equality that gives the proper comparison semantics for every koan. That includes making sure things like sequence equality, tuple equality, and record type equality work in a way that makes sense for every koan. The nice part about the NUnit behavior is that it simplifies the early stages of learning, but it becomes confusing as things differ more and more from F# equality. In this case, it's especially confusing.

In short, it would require a little bit of effort to fix the AssertEquality function to have a consistent idea of equality across all F# types. The more difficult piece is revisiting every koan to make sure there's a good experience for everyone. If I get some time, I'll take a look at fixing it, but until then, I like to leave this as is because it brings up a good conversation about equality semantics.

Chris,

My apologies for the long delay in my reply; I have not signed into this account an a while. I haven't looked at FSharp in a while; it is purely out of interest/intellectual curiosity at the moment and I fit in dabbling with it when I can :0)

I can see the validity of your point about the discussion being raised; once I realised the problem was in the nunit side there was no real issue.

Thanks for your prompt reply though and once again thanks for the time and effort put into the koans in the first place. It is a good way to learn!

AssertEquality result (9.0, 27.0) will let users continue

dsyme commented

Fixed in #51