Monday, May 9, 2011

Lambdas and expression trees in Delphi

Ever wanted to write something like this in Delphi?


Actually in Delphi you have to write it like this.

for cust in customers.Where(
  function(c: TCustomer): Boolean
    Result := c.CustomerId = 'ALFKI';
  end) do ... 





for cust in customers.Where(








  1. OK, this is sweet. I ran across this article a just a couple weeks ago, and then today I had a problem that could be solved best with expression trees.

    Keep up the good work! :)

  2. I am very curious to know what that was, how you solved it and if you ran into any problems or bugs :)

  3. Kind of a long story. Short version: I've been working on converting the storage for my game engine from flat files to a Firebird embedded database. This lets me load stuff into memory a lot faster, because I can use lazy loading instead of reading in the entire file all at once.

    The downside is, I don't have everything loaded into memory all at once. I used to hold all my data in generic TList containers, ordered by ID. Now I can't do that, so I'm using TDictionary<integer, data object> descendants instead, backed by datasets.

    I had a method on the list class called FirstWhere, which takes an anonymous method and returns the first item that matches the criteria. (See FirstWhere in Alex Ciobanu's Enex; I'm the one who gave him the idea for that method.)

    But you can't exactly do that on a TDictionary, especially one without all the elements populated. And you can't use a normal anonymous method to query the dataset that's backing the dictionary, so I reimplemented FirstWhere as taking a TLambda-style expression, then generating SQL from it to apply to the dataset as a Filter, and it worked.

  4. Nice, so basically what I was planning to do with those expressions. No wonder lambda expressions were basically one of the things they implemented to make LinQ work.

    I wonder if it is possible to create some IDE plugin that fakes code completion for custom variant types because Delphi does not have that type safety on dynamic (i.e custom variant types) types.

  5. Similar stuff :)

  6. Same here, I linked to your original post.

  7. I was looking at this a little bit more. Looks to me like this wouldn't be thread-safe, with the expression stack being a global variable...

  8. That is true. And actually I don't like that global variable thing anyway. I will see if I can solve this in some simple way because this whole thing is more of a proof of concept anyway.