Sunday, December 30, 2007

Time to learn grammar (Predicate Delegates)

I was in seventh that time, our Maths teacher entered into the class. He ordered, "Students, who have not completed their assignments, stand outside the class". Unlucky me, like always I went outside the class.

If you noticed after this, we are a group of students standing outside the class; poor we :(. Question to my readers, lets represent this in my favourite subject Mathematics:

{students standing outside the class poor we is a group of students (who have not completed their assignments)}

By this, we want to seperate some specific students (who have not completed their assignments) from the group of students. Means, we create a criteria = who have not completed their assignments and equate this criteria for each of the student in the group, when a student satisfies this criteria he comes into the group of "students standing outside the class" which is our resultset.

This phenomenon in Mathematics is known as Predicate or a Propositional function - which represents the choice of student which returns a proposition which can be either true or false i.e. he has completed his assignment or not.

Few points of our interest:

  • Predicate always applies to a collection, in our case it is "a group of students"
  • Predicate works against a condition/criteria, in our case it is "who have not completed their assignments"
  • Predicate always returns a boolean value (true/false), this is because predicate evaluates against a criteria which can only return true (if a set element satisfies the criteria) or return false (if a set element doesn't satisfies the criteria)

Now we know what is a Predicate ? isn't it :) - similarly we have a special delegate which we call "Predicate Delegate".

What you think a "Predicate Delegate" will be?

This is a a special delegate which will

  1. Always apply to a set (i.e. collection of a specific type of object, in our case it is a group of students)
  2. Always evaluate for each member in the set (i.e. every object in the collection, in our case it is every student)
  3. Always return a boolean value (i.e true or false, in our case when a criteria is met by a student it will return true and vice-versa)

I cannot resist myself from giving a example:

  1. Here is our criteria -
    //A simple criteria which applies only to a student
    public static bool HasDoneAssignment(Student studentToBeEvaluated)
    {
    bool result = false;

    result = studentToBeEvaluate.Assignment.IsComplete;

    return result;
    }
  2. How do we evaluate to this criteria?
    //Evaluate students one by one
    HasDoneAssignment(student1);
    HasDoneAssignment(student2);
    HasDoneAssignment(student3);
  3. What could be a delegate for the same? (hint - its delegate will just be "delegate" keyword suffixed with Method Signature)
    //A simple delegate which accepts student
    public delegate bool HasDoneAssignmentDelegate(student studentToBeEvaluated);
  4. How do we consume this delegate?
    //Instantiate the delegate and point it to our criteria function
    HasDoneAssignmentDelegate evaluateStudentCriteria = HasDoneAssignment;

    //Evaluate studens
    evaluateStudentCriteria(student1);
    evaluateStudentCriteria(student2);
    evaluateStudentCriteria(student3);
  5. Wanna try it using a Predicate Delegate, seems like you want it :)
    //Instantiate Predicate delegate of type <int> and point it to our function
    Predicate<student> evaluateStudentCriteriaUsingPredicateDelegate = HasDoneAssignment;

    //Evaluate numbers
    evaluateStudentCriteriaUsingPredicateDelegate(student1);
    evaluateStudentCriteriaUsingPredicateDelegate(student2);
    evaluateStudentCriteriaUsingPredicateDelegate(student3);

Wow, Can you notice how Predicate delegate is helping us? See the old and the new code:

<Old> HasDoneAssignmentDelegate evaluateStudentCriteria = HasDoneAssignment;

Vs

<New> Predicate<student> evaluateStudentCriteriaUsingPredicateDelegate = HasDoneAssignment;

Conclusion

We can always use a Predicate delegate in lieu of a delegate(function pointer) which takes only one argument and returns a boolean value. That means, any function which accepts a single argument and returns a boolean value can be pointed using Predicate delegates.

Predicate delegate uses another good feature of .NET framework - Generics to facilitate strongly typed input to that particular function.

In real world scenarios, predicate delegates can be used for anything which requires any kind of filtering i.e. AnyCollection>.Find(), <AnyCollection>.FindAll(), etc. I know you can always use for more innovative functionalities across our business applications. :) Clever you..

Quiz for you guys

How do we pass the criteria within the predicate delegate? because you know what predicate delegate doesn't accepts any criteria; since predicate delegates can only have one parameter pointing to the object to which we want to apply the criteria.

For hints you can see my one of the earlier post. In my version of implementation of LINQ like design you will discover how I harness the power of Predicate delegate to implement the Where<> functionality. Can you recall this ?

employees.Where<int>("Salary", 20000);
Hope you enjoyed reading this post, please share your views by giving comments :)

5 comments:

Rajeev said...
This comment has been removed by the author.
Rajeev said...

I guess I lost it in Step 5 but for the time being my 1 liner just aligns properly to my needs :)

students.RemoveAll(new Predicate<Student>(delegate(Student student) { return student.isAssignmentComplete}));

Would need some assistance may be tomorrow you can explain it to me in detail.

Rajeev said...

Ok, may be i should explain why i lost it , we say that the predicate delegate applies to a list but we are passsing student1 student2 which are individual items and not list, what fun will that be if I have to execute it one by one.

Rajeev said...

Yeah things are now clear as Mud :).
Predicate delegate makes a lot of sense from code clealiness perspective.

students.RemoveAll(assignmentIncomplete);

public static bool assignmentIncomplete(Student student)
{
return student.isAssignmentComplete;
}

Like this achieves the same thing as the one liner posted above but truly a lot cleaner.

Saurabh said...

In the example, you are clear in understanding that predicate delegate has to be evaluated one by one for all the students.

Here, the beauty of evaluating predicate delegate for the whole list is provided by List.RemoveAll() not by Predicate Delegate.

Predicate Delegate is just a function which evaluates to a criteria and returns a boolean value.