Here is some unexpected (by me) behaviour in F#. I have a simple class that sorts a sequence :
type MyQueue<'a when 'a : comparison> ( values : 'a[] ) =
let vals =
Seq.sort values
member this.First = Seq.nth 0 vals
override this.ToString() =
Seq.fold ( fun s a -> s + a.ToString() + ";" ) "" vals
I have written a slightly contrived unit test (in C#) to test this:
private class TestObject : IComparable
{
public TestObject( double Value )
{
this.Value = Value;
}
public void Update(double NewValue)
{
this.Value = NewValue;
}
public double Value { get ; private set; }
public int CompareTo(object Comparable)
{
return this.Value.CompareTo( (Comparable as TestObject).Value );
}
public override string ToString ()
{
return Value.ToString();
}
}
[Test]
public void TestUpdate_OK()
{
var nums = new double[]{7,4,3,12,11,3,8};
var values = nums.Select( n => new TestObject(n) ).ToArray();
var q = new MyQueue<TestObject>( values );
Console.WriteLine ( q.ToString() );
// update one of the values in the collection - should not re-sort the collection
values[3].Update( 2.0 );
Console.WriteLine ( q.ToString() );
Assert.AreEqual( q.First.Value, 3.0 );
}
the Seq.sort does sort the sequence, and the first output is correct :
3;3;4;7;8;11;12;
However, updating the test (reference type) object causes the sequence to be re-sorted :
2;3;3;4;7;8;11;
I expected that the vals in the MyQueue object would now be unsorted, since the value in the reference object has changed, but the Seq.sort appears to have been performed again. I don’t understand, I thought the object of functional programming was to avoid side effects. Why do I get this behaviour?
The cause of this is the statement
let vals = Seq.sort valuesis not actually sorting the values until some code consumes the vals variable i.e what your Seq.fold does in toString method, it consumes the vals sequence and at that time the sorting happens and whatever values are there in the values array at that time, those values are sorted, so basically the sorting is happening at the time when you call toString method.Also, I won’t call it FP 🙂 as you are basically doing OOPs by creating type with private state and that state is accessed by type members.
Your problem is related to how sequences works and not in general applicable to FP.