views:

114

answers:

3

Consider my first attempt, a simple type in F# like the following:

type Test() =
    inherit BaseImplementingNotifyPropertyChangedViaOnPropertyChanged()
    let mutable prop: string = null
    member this.Prop
        with public get() = prop
        and public set value =
            match value with
                | _ when value = prop -> ()
                | _ -> 
                    let prop = value
                    this.OnPropertyChanged("Prop")

Now I test this via C# (this object is being exposed to a C# project, so apparent C# semantics are desirable):

[TestMethod]
public void TaskMaster_Test()
{
    var target = new FTest();
    string propName = null;
    target.PropertyChanged += (s, a) => propName = a.PropertyName;
    target.Prop = "newString";

    Assert.AreEqual("Prop", propName);
    Assert.AreEqual("newString", target.Prop);

    return;
}

propName is properly assigned, my F# Setter is running, but the second assert is failing because the underlying value of prop isn't changed. This sort of makes sense to me, because if I remove mutable from the prop field, no error is generated (and one should be because I'm trying to mutate the value). I think I must be missing a fundamental concept.

What's the correct way to rebind/mutate prop in the Test class so that I can pass my unit test?

+3  A: 

Try this:

type Test() =
    inherit BaseImplementingNotifyPropertyChangedViaOnPropertyChanged()
    let mutable prop: string = null
    member this.Prop
        with public get() = prop
        and public set value =
            match value with
                | _ when value = prop -> ()
                | _ -> 
                    prop <- value
                    this.OnPropertyChanged("Prop")

You need to make the binding mutable and then alter its value in your setter. In your initial code, you were just creating a new binding (also called prop) within your setter, so no change was visible.

kvb
Thanks, @kvb. Nothing makes me feel like a n00b at the language than a fix as simple as that. :)
Greg D
@Greg - no problem. The way that bindings and shadowing work can take a bit of getting used to, particularly since other languages do things so differently. However, once you get your mental model straight, I think the elegance of F#'s approach becomes apparent.
kvb
+5  A: 

In your pattern match you are actually binding a new value with

let prop = value

When you bind a value like this with the same name, it will shadow the other value for the scope of the newly declared one. I believe what you actually want to do is this:

prop <- value
TwentyMiles
+4  A: 

As a side-note, I would probably use if .. then instead of the match construct as it makes the code more succinct (patterh matching is especially valuable when you need to test the value agains multiple complex patterns). Also, public is the default access for member, so you can make the code a bit more succinct:

type Test() = 
    inherit BaseImplementingNotifyPropertyChangedViaOnPropertyChanged() 
    let mutable prop : string = null 
    member this.Prop 
        with get() = prop 
        and set(value) = 
            if value <> prop then 
               prop <- value 
               this.OnPropertyChanged("Prop") 
Tomas Petricek
I totally already bought your book. :) Useful reading, though I wish I'd kept it handy when I asked this question!
Greg D