IWETHEY v. 0.3.0 | TODO
1,095 registered users | 1 active user | 0 LpH | Statistics
Login | Create New User
IWETHEY Banner

Welcome to IWETHEY!

New Smalltalk GLORP => Ruby Criteria
A while back Todd mentioned the GLORP system ([link|http://z.iwethey.org/forums/render/content/show?contentid=110881|http://z.iwethey.org...?contentid=110881]) that translated Smalltalk queries into SQL code. He was using it as an example of Message Based OO.

It was an idea that I wanted to play around with, but never had the time. But I did briefly mention the concept on the Ruby IRC channel and Ryan Pavlik took the idea and ran with it. The result is the Criteria Ruby library ([link|http://mephle.org/Criteria/|http://mephle.org/Criteria/]).

Here's a short example ...
  require 'criteria/sql'\n  include Criteria\n\n  person = SQLTable.new("person")\n  query = person.age >= 21 & person.salary > 5000.00\n  puts query.select(person.name)
will print
  SELECT person.name FROM person WHERE ((person.age >= 21) AND (person.salary > 50000))
It is interesting where conversations that pass through this forum end up.
--
-- Jim Weirich jweirich@one.net [link|http://onestepback.org|http://onestepback.org]
---------------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
New Looks pretty cool
I think it would be cooler if you didn't have to specify what kind of thing your were going to query up front and there were an implicit mapping to class (rather than exposing the table name). But I guess you could hide that in some kind of factory method.

I've got a similar mechanism in java based on NSQualifier (NextStep class). It doesn't do the message logging trick, but it lets you specify a query as a string, then compiles that into an expression tree using the interpreter pattern.

Qualifier q = new Qualifier("name == 'todd' && children.name *= 'Eileen');
List matches = q.filteredList(listOfPeople);

Implementing double dispatch (visitor for you C++/JHeads) you throw a SQLArchiver at the qualifier and it walks the expression writing sql as it goes.

So there are lots of ways to skin this cat.



Java is a joke, only it's not funny.

     --Alan Lovejoy
New OT: double dispatch?
I've seen the term, and used packages that said they implemented it, but missed the class where it was defined.
===

Implicitly condoning stupidity since 2001.
New double dispatch example
Double dispatch is used when you would really like to dispatch on two different objects at the same time.

Example: Suppose you were manipulating geometric shapes (Bryce will love this example), and you wanted to determine the intersection of two arbitrary shapes.
def process(shape1, shape2)\n  shape1.intersect(shape2)   # This is the first dispatch\nend
Now, the way an intersection is caculated is different depending on your shapes. For example, finding the intersection of two rectangles is done differently from finding the intersection of two circles, which in turn is different from a rectangle and a circle.

Now, if we know the type of one of the shapes, the algorithm is easy to write for any other shape. For example:
  class Rectangle\n    def intersect_rectangle(rect)\n      puts "Intersecting a Rectangle and a Rectangle"\n    end\n\n    def intersect_circle(circle)\n      puts "Intersecting a Rectangle and a Circle"\n    end\n  end\n\n  class Circle\n    def intersect_rectangle(rect)\n      puts "Intersecting a Circle and a Rectangle"\n    end\n\n    def intersect_circle(circle)\n      puts "Intersecting a Circle and a Circle"\n    end\n  end\n
Notice that each type knows how to intersect itself with both a circle and a rectangle.

Suppose I execute the code: rect.intersect(shape)? We dispatch to the retangle's intersection (this is the first dispatch). We don't know the type of shape, but we do know the type of self (which is a rectangle). Well, the problem is simple if we know one of the type (which we do). We just dispatch again. Here is the intersection code for rectangle:
  class Rectangle\n    def intersect(shape)\n      shape.intersect_rectangle(self)  # this is the second dispatch\n    end\n  end
The code for circle is a mirror image.
  class Circle\n    def intersect(shape)\n      shape.intersect_circle(self)  # this is also a second dispatch\n    end\n  end
Finally, we put it together:
  c1 = Circle.new\n  c2 = Circle.new\n  r1 = Rectangle.new\n  r2 = Rectangle.new\n\n  process(c1,c2)\n  process(r1, r2)\n  process(r1, c1)\n  process(c1, r1)
And the output is
  Intersecting a Circle and a Circle\n  Intersecting a Rectangle and a Rectangle\n  Intersecting a Circle and a Rectangle\n  Intersecting a Rectangle and a Circle
In short, double dispatch is a way of doing type discovery.

Advantages: it is fast and bounded. It takes just two polymorphic calls to resolve the types. A dynamic cast in Java or C++ is generally slower and depends on the shape of the inheritance tree.

Disadvantages: the number of dispatching methods grows with the square of the number of types to distinquish.
--
-- Jim Weirich jweirich@one.net [link|http://onestepback.org|http://onestepback.org]
---------------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
New ahh, thanks
===

Implicitly condoning stupidity since 2001.
New Yep - its all through the numerics
That's the best example I know of. You have two numbers - you want to add them - but adding a couple of ints is different from adding an int and a float, or an int and a fraction (fractions are first class numbers in ST) or adding an int and a point....

In Java a small subset of what ought to be implemented in Number would look like:

class Number
{
Number add(Number n);
Number addInteger(Number n);
Number addFloat(Number n);

int intValue();
float floatValue();
}

class Integer extends Number
{
Number add(Number n) { n.addInteger(this); }
Number addInteger(Number n) { return new Integer(n.intValue() + this.intValue()); }
Number addFloat(Number n) { return new Float(n.floatValue() + this.floatValue()); }
}

class Float extends Number
{
Number add(Number n) { n.addFloat(this); }
Number addInteger(Number n) { return new Float(n.floatValue() + this.floatValue()); }
Number addFloat(Number n) { return new Float(n.floatValue() + this.floatValue()); }
}

So if I have a pair of Integers

Number n1 = new Integer(3);
Number n2 = new Integer(5);

Number n3 = n1.add(n2);
calls:
n1.add(n2) // neither concrete type is known here - within this call n1 (an integer) will identify its concrete type to n2
n2.addInteger(n1) // by telling it to addInteger to itself - n2 knows its type and does the right thing

Its very slick but the number of methods does indeed grow exponentially with the number of types. So its only really practical up to maybe 10 types or so.





Java is a joke, only it's not funny.

     --Alan Lovejoy
New Re: Looks pretty cool
Todd: I think it would be cooler if you didn't have to specify what kind of thing your were going to query up front and there were an implicit mapping to class (rather than exposing the table name).

You don't have to specify the thing up front. The following (longer) example creates the query early, then uses the same query object to search an array and to generate SQL.
  query = proc { |t| t.age >= 21 }\n  \n  require 'criteria/array'\n  require 'criteria/sql'\n  include Criteria\n  \n  Person = Struct.new(:name, :age)\n  class Person\n    def to_s()\n      "#{name} (#{age})"\n    end\n  end\n  \n  people = [ Person.new("Jim", 46), Person.new("Dan", 18) ]\n  \n  t1 = ArrayTable.new(people)\n  t2 = SQLTable.new("person")\n\n  puts query.call(t1).select  # Search an array\n  puts query.call(t2).select  # Generate SQL
Output is
  Jim (46)\n  SELECT * FROM person WHERE (person.age >= 21)
BTW, it looks like Ryan was doing something in this area before our IRC conversation. He credits something called Junction as the inspiration for Criteria.
--
-- Jim Weirich jweirich@one.net [link|http://onestepback.org|http://onestepback.org]
---------------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
     Smalltalk GLORP => Ruby Criteria - (JimWeirich) - (6)
         Looks pretty cool - (tuberculosis) - (5)
             OT: double dispatch? - (drewk) - (3)
                 double dispatch example - (JimWeirich) - (1)
                     ahh, thanks -NT - (drewk)
                 Yep - its all through the numerics - (tuberculosis)
             Re: Looks pretty cool - (JimWeirich)

"It grew, as the sum of a lot of separate people's ad-hockery, most of those by people who had no idea what they were doing, and would gladly pound screws with a hammer all year long, for lack of acquaintance with the concept of screwdrivers." - Rick Moen
51 ms