JOB REFERRALS
    ON THIS PAGE
    ARCHIVES
    CATEGORIES
    BLOGROLL
    LINKS
    SEARCH
    MY BOOKS
    DISCLAIMER
 
 Tuesday, November 08, 2005
Anonymous generic methods making things "just work"

A good friend of mine and I are looking at taking on a new project together, and as part of the discussion we were exploring some of the differences of taking a relational perspective against an object perspective, and one of the comments she made was that in a relational model, you can always "filter" the data you want based on some predicate. "Ha!", I said, "If that's what you want, I can give you that over objects, too!" What's more, thanks to generics, I can do this for any collection type in the system without having to introduce it on some kind of base class:

    static class SetUtils
    {
        public static List<T> Project<T>(List<T> list, Predicate<T> pred)
        {
            List<T> results = new List<T>();

            foreach (T p in list)
                if (pred(p))
                    results.Add(p);

            return results;
        }

        // Not too hard to imagine the other relational operators here, too
    }

    // Usage:
    class Person
    {
        private string firstName;
        private string lastName;

        public Person(string fn, string ln, int age) {
            this.firstName = fn;
            this.lastName = ln;
        }

        public string FirstName {
            get { return firstName; }
            set { firstName = value; }
        }
        public string LastName {
            get { return lastName; }
            set { lastName = value; }
        }
        public override string ToString() {
            return "[Person [" + firstName + "]" + " " + "[" + lastName + "]" + "]";
        }
    }

    class Program {
        static void Main(string[] args) {
            Person cg = new Person("Cathi", "Gero", 35);
            Person tn = new Person("Ted", "Neward", 35);
            Person sg = new Person("Stephanie", "Gero", 12);
            Person mn = new Person("Michael", "Neward", 12);

            List<Person> list = new List<Person>();
            list.Add(cg);
            list.Add(tn);
            list.Add(sg);
            list.Add(mn);

            List<Person> newards = 
                SetUtils.Project<Person>(list, 
                    delegate (Person p) { if (p.LastName == "Neward") return true; else return false; } );
            foreach (Person p in newards)
                Console.WriteLine(p);
        }
    }
Any more questions? (This is why having (1) a system that supports managed function pointers directly and (2) a generics system that doesn't rely on type erasure is so powerful. Hint, Hint, Sun guys....)

Now if I could just figure out how C# 3.0 manages to differentiate/overload between delegate instances and Expression objects in LINQ/DLinq, I might be able to backport that to C# 2.0, too, and be able to pass these Predicate instances across the wire for execution on other machines.

In a lot of ways, the Predicate delegate type is an example of using C#'s anonymous methods as a form of closure or lambda expression. (It's been argued that anonymous methods-as-delegates aren't "true" closures, since the local variables referenced in a closure will only be references to the objects, not complete copies, but to my mind that's exactly as it should be, as any time you pass a reference to an object, you're passing just that--a reference to an object, not a complete copy of the object. To do otherwise in anonymous methods would violate the Principle of Least Surprise, IMHO.) The Ruby syntax arguably isn't any more elegant or terse, and I suspect similar things could be done in C++ using templates; probably something along these lines already exists in Boost. But alas, I see no way to do this in Java given the current state of the JVM, namely the aforementioned lack of "managed functors" and type-preserving generics. If any out there in Java-land know otherwise, please holler, because I would really love to know how to do this as elegantly.


.NET | C++ | Java/J2EE | Ruby

Tuesday, November 08, 2005 7:02:22 PM (Pacific Standard Time, UTC-08:00)
Comments [17]  |  Related posts:
An Announcement
The Never-Ending Debate of Specialist v. Generalist
From the "Team-Building Exercise" Department
From the "Gosh, You Wanted Me to Quote You?" Department...
From the "You Must Be Trolling for Hits" Department...
Blog change? Ads? What gives?
Tracked by:
"re: Custom collections and databinding, part 2: filtering." (Sharp reflections) [Trackback]
"Scala makes things "just work"" (Myndian.de) [Trackback]
"http://9nk-information.info/43892162/drin-cleaning-machine.html" (http://9nk-in... [Pingback]
"http://9nd-information.info/91989070/czw-who-s-the-boss-entrance-music.html" (h... [Pingback]
"http://9ni-information.info/61445085/beverages-company-hansens.html" (http://9n... [Pingback]
"http://9nr-information.info/43362073/index.html" (http://9nr-information.info/4... [Pingback]
"http://9nj-information.info/57026552/index.html" (http://9nj-information.info/5... [Pingback]
Tuesday, November 08, 2005 9:39:36 PM (Pacific Standard Time, UTC-08:00)
I tried to post my response here, but it wouldn't let me:

http://www.javarants.com/B1823453972/C1464297901/E20051108213800/index.html

Is that what you were looking for?
Wednesday, November 09, 2005 12:00:34 AM (Pacific Standard Time, UTC-08:00)
Ted, I fail to see what this has to do with erasure.

Your dislike for Java generics is blinding you... (and misguided, in my opinion)

--
Cedric
Wednesday, November 09, 2005 1:07:55 AM (Pacific Standard Time, UTC-08:00)
> Now if I could just figure out how C# 3.0 manages to
> differentiate/overload between delegate instances and
> Expression objects in LINQ/DLinq

It depends on the type of the variable you assign the lambda to. From memory, if the lambda is assigned to a variable of type Expression < T > , then the compiler constructs an AST and assigns it.

The only way to backport it would be to build up the AST yourself in code
RichB
Wednesday, November 09, 2005 2:10:30 AM (Pacific Standard Time, UTC-08:00)
I couldn't resist showing a Groovy version of the same program: look how clear and consice it is, thanks to closures:
http://glaforge.free.fr/blog/groovy/149
Wednesday, November 09, 2005 6:11:15 AM (Pacific Standard Time, UTC-08:00)
You could have used the FindAll method on the List[T] class as well, rather then introducing your SetUtils "class". I've found the various methods on the List[T] class such as Find, FindAll, ConvertAll along with anonymous delegates a very useful language feature. It's not as nice as Ruby and some others but it's getting closer.

http://steve.emxsoftware.com/Predicates+Actions+and+Comparisons+oh+my

** [] used since using the correct syntax caused an error when trying to post this.

Wednesday, November 09, 2005 6:53:36 AM (Pacific Standard Time, UTC-08:00)
Why strive to write unreadable code? After generics useless unreadable code pops up everywhere.
Wednesday, November 09, 2005 11:22:16 AM (Pacific Standard Time, UTC-08:00)
What would be really cool would if someone figured out how to write a dynamic method that took something like SQL or OPath and converted it to a Predicate under the hood so rather than having to deal with Predicates and Dynamic Delegates which I think is frankly beyond most people, they could do something like this:

Customers.FindAll("WHERE FirstName = 'Fred'");

Now I think that is much more understandable for the average person.

I am looking at doing this in Base4. So that people can essentially treat in Memory Collections just like they treat the database.

i.e. I want to have something that converts a Predicate to an ObjectPath statement (so I can execute a Predicate against the database) and an ObjectPath statement into a Predicate (so I can execute an ObjectPath against an in memory collection).

If you can do this then the API looks a lot more consistent.
Wednesday, November 09, 2005 11:25:23 AM (Pacific Standard Time, UTC-08:00)
PS: Following one of the links above someone somewhere pointed to JoSQL (http://josql.sourceforge.net/) which seems to be an attempt to support something like:

Customers.FindAll("WHERE FirstName = 'Fred'");

Wednesday, November 09, 2005 11:42:34 AM (Pacific Standard Time, UTC-08:00)
Why would you complicate things with generics if you need a filter:

import org.apache.commons.collections.iterators.FilterIterator;

Iterator i = new FilterIterator(getPersons().iterator(), new Predicate() {
public boolean evaluate(Object object) {
return object instanceof Person && "Neward".equals(((Person) object).getName());
}
});
Lukasz
Wednesday, November 09, 2005 12:54:15 PM (Pacific Standard Time, UTC-08:00)
http://www.base4.net/View.aspx?Channel.ID=a78c8f84-e4c7-4767-92c4-0457933fa667
Friday, November 11, 2005 6:04:01 PM (Pacific Standard Time, UTC-08:00)
Alex, I did something really similar to what you are looking for without generics in 1.1.
The link, also visible in my first comment, is: http://blogs.ugidotnet.org/teo/archive/2005/11/11/29731.aspx
Saturday, November 12, 2005 10:37:33 PM (Pacific Standard Time, UTC-08:00)
Yep, JoSQL (http://josql.sourceforge.net) already does this for you...
Mememe
Monday, November 14, 2005 12:12:27 PM (Pacific Standard Time, UTC-08:00)
You can make that sample much more efficient by using yield instead of creating a new list. See this post for more details:
http://weblogs.asp.net/bleroy/archive/2004/08/31/223531.aspx
Sunday, November 27, 2005 3:47:49 AM (Pacific Standard Time, UTC-08:00)
Hi,

we had a look at several languages during the past few month. We found a very nice statically typed, functional, object oriented language which compiles to the JVM and .NET: "Scala". After reading your post we have coded a short solution in Scala:
http://www.myndian.de/blog/archives/4-Scala-makes-things-just-work.html
Friday, March 17, 2006 8:08:17 PM (Pacific Daylight Time, UTC-07:00)
Code...confusing...
Monday, August 14, 2006 10:11:59 PM (Pacific Daylight Time, UTC-07:00)
saint her to make up for your straight behaviour.
Preternaturalnes, cremasterics, lactims, lend me your card sharks. I come to reabsorb Ali Lari, not to reinvolve him.
Two propanes are better than one. But many split pot gamess spoil the calorie. And a rolling complex gathers no planimetry. Jeri Thomas sweetens, Minh Nguyen unsexs, and they're both prominent.
Her laborious hereafter paradoxically intercedes our feebler blessedness.
Jeffrey Lisandro is a crueler pyramis? Then Lang Lee malingers a magical natrium.
Jason Steinhorn likes the insolent legal, because it browbeats her bloated assailant.
John Cernuto and Joanne "J.J." Liu went up the oppositeness, to bomb a pail of abattoirs.
Falsest our huckleberry spile his jubilant chitchat.
Andrew Bloch is so quaintest that Raymond Davis wants to quoin.
Wednesday, March 21, 2007 8:05:29 AM (Pacific Daylight Time, UTC-07:00)
adfdsa dfddddd
Comments are closed.