views:

289

answers:

1

Hello,

I am trying to create an overloaded Add method as an extension to the OrderedDictionary class and would like to add the key/value based on some curried predicate.

The calling code would look like this:


OrderedDictionary dict = new OrderedDictionary();

Predicate<int> lessThan5 = i=>; i < 5;
Predicate<string> lenOf2 = s=> s.length == 2;

dict.Add("01","Name", lessThan5 );
dict.Add("02","place", lenOf2);

I have created an extension method like so:


public static class CollectionExtensions
{
    public static void Add(this OrderedDictionary s, string k, string v, Predicate p)
    {
        if (p)
        {
            d.Add(k, v);
        }
    }
}

But it doesn't work because I get a compiler error reading "cannot convert Predicate to bool".

Does anyone know what I am missing?

Thanks for any help. -Keith

+3  A: 

The issue is that you are not evaluating your predicate to check and see whether or not the predicate is satisfied. Now, it's not clear from your question if you want the predicate to test the key or the value. The following checks the key. You should also consider having the method return bool indicating success or failure as I've done here.

static class OrderedDictionaryExtensions {
    public static bool Add(
        this OrderedDictionary dictionary,
        string key,
        string value,
        Predicate<string> predicate
    ) {
        if (dictionary == null) {
            throw new ArgumentNullException("dictionary");
        }
        if (predicate == null) {
            throw new ArgumentNullException("predicate");
        }
        if (predicate(key)) {
            dictionary.Add(key, value);
            return true;
        }
        return false;
    }
}

Usage;

// dictionary is OrderedDictionary
dictionary.Add("key", "value", s => s.Length < 5);

You can actually generalize this a bit since OrderedDictionary is not strongly-typed.

static class OrderedDictionaryExtensions {
    public static bool Add<TKey, TValue>(
        this OrderedDictionary dictionary,
        TKey key,
        TValue value,
        Predicate<TKey> predicate
    ) {
        if (dictionary == null) {
            throw new ArgumentNullException("dictionary");
        }
        if (predicate == null) {
            throw new ArgumentNullException("predicate");
        }
        if (predicate(key)) {
            dictionary.Add(key, value);
            return true;
        }
        return false;
    }
}

Usage:

// dictionary is OrderedDictionary
dictionary.Add(17, "Hello, world!", i => i % 2 != 0);
Jason
+1 Nice examples though could be improved with direct statements of what is wrong with the OP's code: `if` takes bool, so don't pass it anything else. A predicate ought to have a type argument. A delegate must be explicitly called (and passed any required arguments) to execute it - as you say, are we supposed to be testing the key or the value? And if we can't tell, how could the compiler?
Daniel Earwicker
Thanks, Jason. I am new to the concept of functional programming so forgive me if I'm not being clear.The predicate value should have nothing to do with the key or value parameters. I want the predicate function to curry a value.I want to do something like this:Predicate<User> showPlaces = new Predicate<User>(u => u.isAllowed);Preicate<int> showPeople = new Predicate<int>(i => i == 5);then pass the showPlaces or showPeople predicate as a parameter to a method that will evaluate it without passing any parameters....if (p) d.Add(k,v);
Keith
@unknown (google): A predicate is a function mapping some set to `{ true, false }`. Predicates don't have a truth value; you get truth values out of them by evaluating them at some member of their domain. Thus, when you say `Predicate<int> p = new Predicate<int>(i => i == 5)` you must note that `p` does not have a truth value. If you want a truth value out of `p` you have to evaluate it at some `int`.
Jason
Now, to curry a function effectively means to hold one of its parameters constant. So for a predicate which only has one parameter to begin with, this means reducing the predicate to a single value either `true` or `false`. So if that's all you want, why not just make your method above accept a `bool`? But then, in that case, why are you even calling the method? If the `bool` is false, don't bother calling `Add` otherwise do call `Add`.
Jason
Great comments. Thanks!
Keith