Tuesday, October 26, 2010

Union, Tangencies and Colors


Union, Tangencies and Colors

I like the picture below very much.



What you see here are, more or less, pink, green and blue. The colors are chosen as such that they always form distinct colors, regardless of how you combine them. There are of course other combinations with these properties, but... this is at least one of them.

When the pink layer is slightly moved to the right, you see better how the image is constructed:



The pink (transparent) layer is the union of the two underlying (multi-)polygons, the green one and the blue one. It has one hole, one kind of indentation and for the rest it is square. The underlying multi-polygons are better seen if the pink one is removed:



So this is clear: there are two multi-polygons here, complete with holes and self-tangencies. These multi-polygons have overlap in some places, no overlap in other places. They nearly fill the area, there are only three "boxes" free. The blue and green colors nicely mix into blue-green. The colors and transparencies are selected for that. SVG definitions are:

Green: style="fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:3"

Blue: style="fill-opacity:0.3;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:3"

I like this combination.

And with the pink style on top of it...

Pink: style="fill-opacity:0.2;stroke-opacity:0.4;fill:rgb(255,0,0);stroke:rgb(255,0,255);stroke-width:8"

...all colors change, however, they are still clearly distinct. Yellow-orange like for green+pink; lila for blue+pink; and brown for the blue+green+pink. So we have seven unique distinct colors now, which happens to be the ideal number of colors for a map.

By the way, this image is created using Boost.Geometry. Boost.Geometry can easily create SVG images. And Boost.Geometry can overlay multi-polygons (already possible for a long time) having all kinds of self-tangencies (new!). A self-tangency in a multi-polygon is a place where two polygon-members touch each other (orange dots in the map below), or where a polygon touches itself (the red dot in the map).



Actually... this could also be a polygon, having five interior rings (holes) which might be mutually tangent and tangent to they exterior ring.


OK, one more image...



Tuesday, October 19, 2010

Tag Dispatching and Inheritance

Tag Dispatching and Inheritance


In the previous blog we described Tag Dispatching by Type.

Though very convenient, when many classes (tagged by as many tags) share the same implementation, we get as many dispatch structs with the same implementation (or, better, forwarding to the same struct). This can be avoided by using similarities between classes, or between tags. In Boost.Geometry, for example, some geometries are single while others are multi. That multi-ness can be recognized by the metafunction is_multi which results in true for a multi-polygon and in false for a single polygon. We can include an IsMulti boolean template parameter in the dispatch structure, so that it is selected not only on tag dispatching, but also in is_multi.

This similarity can also be implemented using a tag hierarchy and inheritance.

Let's go back to the fruit example. All citrus fruit species have pulp vesicles. There are many citrus fruits species. And, of course, we don't want to repeat the dispatch structure has_vesicles so many times. So we try to define our tag hierarchy:

struct citrus_tag {};
struct pome_tag {};

struct apple_tag : pome_tag {};
struct pear_tag : pome_tag {};

struct
banana_tag {};

struct orange_tag : citrus_tag {};
struct lemon_tag : citrus_tag {};
struct lime_tag : citrus_tag {};

And then we couple the tags, like we did in previous blog:

template <typename T> struct tag {};
template <> struct tag<apple> { typedef apple_tag type; };
template <> struct tag<pear> { typedef pear_tag type; };
template <> struct tag<orange> { typedef orange_tag type; };
template <> struct tag<lime> { typedef lime_tag type; };
template <> struct tag<banana> { typedef banana_tag type; };

The new thing, besides the inheritance in the tags above, is that we now define a tag_cast metafunction:

template
<
    typename Tag, typename BaseTag,
    typename BT2 = void, typename BT3 = void, typename BT4 = void,
    typename BT5 = void, typename BT6 = void, typename BT7 = void
>
struct tag_cast
{
    typedef typename boost::mpl::if_
        <
          typename boost::is_base_of<BaseTag, Tag>::type,
          BaseTag,
          // Try next one in line:
          typename tag_cast<Tag, BT2, BT3, BT4, BT5, BT6, BT7, void>::type
        >::type type;
};

template <typename Tag>
struct tag_cast<Tag, void, void, void, void, void, void, void>
{
    // If not found, take specified tag, so do not cast
    typedef Tag type;
};

We can now check if a tag is a citrus tag, by calling defining a new tag as tag_cast<tag, citrus_tag>::type. This new tag is either a citrus tag, or it is the tag it already was.

And we can dispatch by this tag as well. So it looks like:

namespace dispatch
{
    template <typename T> struct has_vesicles : boost::false_type {};
    template <> struct has_vesicles<citrus_tag> : boost::true_type {};
}

template <typename Fruit>
std::string has_vesicles(Fruit const& fruit)
{
    // (Potentially) go up in hierachy: take tag corresponding to Fruit,
    // downcast to citrus_tag if possible
    typedef typename tag_cast<typename tag<Fruit>::type, citrus_tag>::type tag;

    return std::string("has vesicles: ")
        + (dispatch::has_vesicles<tag>::value ? "true" : "false");
}

This tag_cast, as proposed above, can not only cast to one base-class, but also to a range of base-classes. The definition
 typedef typename tag_cast<typename tag<Fruit>::type, citrus_tag, pome_tag>::type tag;
will result in a citrus_tag if it is a citrus, a pome_tag if it is a pome, and otherwise it results in the input tag. Besides this, it also walks through a tag hierarchy, so if citrus_tag and pome_tag were both derived from, e.g., a rosid_tag, and rosid_tag was specified in this call, it would result in a rosid_tag.

The sample program here shows two base classes, not listed here.

Our main program now displays correctly if the specific fruits have vesicles or not

int main()
{
    using namespace fruit;

    apple a("my apple");
    pear p("my pear");
    orange o("my orange");

    std::cout << has_vesicles(a) << std::endl;
    std::cout << has_vesicles(p) << std::endl;
    std::cout << has_vesicles(o) << std::endl;

    return 0;
}

Back to Boost.Geometry. Until now it is not done, but we might depricate the is_multi meta-function and replace it by this:

struct multi_tag;
struct multi_point_tag : multi_tag {};
struct multi_linestring_tag : multi_tag {};
struct multi_polygon_tag : multi_tag {};

And instead of calling is_multi, we call tag_cast<tag, multi_tag>. We then know if it is a multi and can dispatch on it. The same for linear. This will probably be very convenient, it has to be worked out a little more.


Casting and (multiple) inheritance
The tag_cast as implemented above casts to specified tags. We can not just call the parent-tag. One of the reasons for this is multiple inheritance.
Tag inheritance can be multiple. This is convenient because, of course, there can be different tag classifications for the same set of tags. For example: if a geometry contains segments, or is linear, or is areal. So we might get:

struct multi_tag;
struct multi_point_tag : multi_tag {};
struct multi_linestring_tag : multi_tag, linear_tag {};
struct multi_polygon_tag : multi_tag, areal_tag {};
When calling tag_cast, the results depends on the order of the specified base tags. And so does the dispatching.


Tag Dispatching by Type

Tag Dispatching by Type


Tag Dispatching (TD) is a Generic Programming (GP) technique for C++. It is well explained in this blog. Google Hit Number one (GH#1) is this site, where the example of the STL function advance is given. Tag Dispatching is not described a lot; GH#7 is from ggl (= Boost.Geometry), as is GH#8..

Nearly all TD descriptions I know of use the example of STL-advance. But in Boost.Geometry TD is done in another way: not by instance, but by type. The difference is explained in this blog.

Suppose you make a generic program doing something with fruit. An apple is normally being eaten differently than a banana or an orange. So if we program a generic function eat, giving it any type of fruit, it should redirect this to an implementation specific to that kind of fruit, so for apple differently than for a banana.

We first implement the tags. Tags are completely empty structures. But (of course) not completely useless.
struct apple_tag {};
struct banana_tag {};
struct orange_tag {};

We then create some sample implementations. Most properties are not used, it is just to show there are (sometimes completely) different classes which can be handled genericly.
struct apple
{
    double radius;

    std::string name;
    apple(std::string const& n) : name(n) {}
};

struct banana
{
    double length;

    std::string name;
    banana(std::string const& n) : name(n) {}
};


All this is quite simple C++ code, though you have to understand templates (generics) and specialization.

OK, now we implement Tag Dispatching by Instance:

namespace dispatch
{
    void eat(apple const& a, apple_tag)
    {
        std::cout << "bite" << std::endl;
    }

    void eat(banana const& b, banana_tag)
    {
        std::cout << "peel" << std::endl;
    }
}

template <typename T>
void eat(T const& fruit)
{
    typename tag<T>::type the_tag;
    dispatch::eat(fruit, the_tag);
}

The function eat at the bottom first declares an instance of the tag. If an apple is entered in this function, it will be an instance of the apple_tag. If a banana is entered, it is a banana_tag. Then it forwards its call to the eat function in the namespace dispatch. There are two versions (overloads) there, one specified with an apple_tag, one with a banana_tag. The compiler selects, based on the tag the right function. Quite easy, and quite powerful, this tag dispatching system.

As said, within Boost.Geometry it is not applied like this. One of the reasons is that the instance of the tag is not necessary at all. If the dispatch::eat function would be implemented within a struct, as a static method, the tag dispatching can be done by type and not by instance. This is still tag dispatching!

So the piece above can be replaced by this Tag Dispatching by Type:

namespace dispatch
{
    template <typename Tag> struct eat {};

    template <> struct eat<apple_tag>
    {
        static void apply(apple const& a)
        {
          std::cout << "bite" << std::endl;
        }
    };

    template <> struct eat<banana_tag>
    {
        static void apply(banana const& b)
        {
          std::cout << "peel" << std::endl;
        }
    };
}

template <typename T>
void eat(T const& fruit)
{
    dispatch::eat<typename tag<T>::type>::apply(fruit);
}

So no instance at all, type only. Boost.Geometry has this structure everywhere, and all static dispatching methods are called apply.

For completeness we list the main program as well here:
int main()
{
    apple a("my apple");
    banana b("my banana");
    eat(a);
    eat(b);

    return 0;
}

It is the same for the instance-version and the type-version.

More advantages of the Tag Dispatching by Type approach are that arguments can be reversed, so you can call distance(point, polygon) and distance(polygon, point) but there is only one implementation with point_tag, polygon_tag necessary. With instances (and function overloads) this is not possible, or at least not that easy. Furthermore, tag dispatching by type can be used to define types, or define constants, as well. Suppose you need to define a constant value dependant on a type. We approach geometry now and want to define if a specific fruit-type is spherical or not. So we define this structure, specialized by tag:
    template <typename Tag> struct spherical {};

    template <> struct spherical<apple_tag>
    {
        static const bool value = true;
    };

    template <> struct spherical<banana_tag>
    {
        static const bool value = false;
    };

We can create a generic structure, which calls this dispatch, just like the free function eat, but now with a struct (or meta-function):

template <typename T>
struct spherical
{
    static const bool value = dispatch::spherical<typename tag<T>::type>::value;
};


Next blog will handle Tag Dispatching and Inheritance.


Monday, July 26, 2010

C# Specializations by Traits IV


C# Specializations by Traits IV


Geometry

In last three blogs (I'm productive these days in blogs, instead of klocs) I explained how to to specializations in C#. This blog only explains how it begon, give different possibilities to design things, and wraps it up.


Towards specializations

Developing Boost.Geometry, in C++, and doing some more C# this year as well, I wondered how a generic geometry library in C# would look like. Ideally it would be as Boost.Geometry, of course... But Boost.Geometry is based on traits and C++ specializations, partial specializations, tag dispatching. All modern C++ generic programming stuff. Not easily doable in C#.

Calculating the distance between two arbitrary point types would already be something. I tried many methods, and discussed them with my collegue Paul den Dulk, and he helped me, suggesting more methods and some essential pieces. Putting it together, adding the dictionary as the runtime register instead of the compiletime C++ specializations, the point distance function is looking exactly the same as Boost.Geometry now!

Some notes

There are still many differences from this system with C++ specializations, of course.
  • in C++ it is compile-time and checked at compile-time
  • therefore in C++ it is very fast
  • in C# the dictionary is runtime and checked at runtime
  • because the dictionary lookup and necesary cast it is slower in C#
  • C++ has partial specializations, don't know (yet) how to do that in C#
  • C++ has type calculations, the whole template metaprogramming is based on that. 
  • in C# it is only the methods
  • because in C# it is runtime, it gives some advantages as well: you can register different traits classes when needed
  • and so, e.g. the ORM can handle the same model in different ways

Timings

As said the dictionary consultation, together with the cast, take some time. Using the geometry case distance, I timed it and it is certainly measurable.

Ten million distance calculations on my computer:
  • Using interfaces: 0.10 seconds
  • Using delegates: 0.15 seconds
  • Using traits: 0.13 seconds
  • Using a register: 0.42 seconds
So, in fact 4 times slower. It is much in this case, but this is compared to a small calculation (Pythagoras). If applied using GUI, database, disk io, or occasionally (and not 10 million times), the lookup will probably fall away.

Complete program

The program to research, with 10 possible implementations, with interfaces, wrappers, delegates, traits, registers and lambdas, is shown below.

using System;
using System.Diagnostics;

using System.Collections.Generic;


namespace GenericGeometry
{
    interface IPoint
    {
        double x();
        double y();
        void increase();
    }

    delegate double get_x<Point>(Point p);
    delegate double get_y<Point>(Point p);

    public interface ITraitsBase {}

    public interface ITraits<Point> : ITraitsBase
    {
        double get_x(Point p);
        double get_y(Point p);
    }

    class TraitsRegister
    {
        public static IDictionary<Type, ITraitsBase> register;

        public static void Register<PointType>(ITraits<PointType> t)
        {
            if (register == null)
            {
                register = new Dictionary<Type, ITraitsBase>();
            }
            register[typeof(PointType)] = t;
        }
    }

    class LambdaRegister
    {
        public static IDictionary<Type, Tuple<object, object>> register;

        public static void Register<Point>(get_x<Point> gx, get_y<Point> gy)
        {
            if (register == null)
            {
                register = new Dictionary<Type, Tuple<object, object>>();
            }
            register[typeof(Point)] = new Tuple<object, object>(gx, gy);
        }
    }


    // The generic library, with functions as "Distance", working on IPoint or on any point
    class Algorithm
    {
        // (1) Using an interface to access coordinates
        public static double Distance(IPoint p1, IPoint p2)
        {
            double dx = p1.x() - p2.x();
            double dy = p1.y() - p2.y();
            return Math.Sqrt(dx * dx + dy * dy);
        }

        // (7) use delegates to access coordinates of not interfaced point type
        public static double Distance<Point>(Point p1, Point p2,
            get_x<Point> gx,
            get_y<Point> gy)
        {
            double dx = gx(p1) - gx(p2);
            double dy = gy(p1) - gy(p2);
            return Math.Sqrt(dx * dx + dy * dy);
        }

        // (8) use traits/accessor to access coordinates of not interfaced point type
        public static double Distance<Point>(Point p1, Point p2, ITraits<Point> traits)
        {
            double dx = traits.get_x(p1) - traits.get_x(p2);
            double dy = traits.get_y(p1) - traits.get_y(p2);
            return Math.Sqrt(dx * dx + dy * dy);
        }

        // (9) use traits/REGISTER accessor to access coordinates of not interfaced point type
        public static double DistanceTR<Point>(Point p1, Point p2)
        {
            ITraits<Point> traits = TraitsRegister.register[typeof(Point)] as ITraits<Point>;
            double dx = traits.get_x(p1) - traits.get_x(p2);
            double dy = traits.get_y(p1) - traits.get_y(p2);
            return Math.Sqrt(dx * dx + dy * dy);
        }

        // (10) use (tupled) lambda/REGISTER accessor to access coordinates of not interfaced point type
        public static double DistanceLR<Point>(Point p1, Point p2)
        {
            var pair = LambdaRegister.register[typeof(Point)] as Tuple<object, object>;
            get_x<Point> gx = pair.Item1 as get_x<Point>;
            get_y<Point> gy = pair.Item2 as get_y<Point>;
            double dx = gx(p1) - gx(p2);
            double dy = gy(p1) - gy(p2);
            return Math.Sqrt(dx * dx + dy * dy);
        }
    }


    // (1) implement IPoint
    class MyPoint1 : IPoint
    {
        private double m_x, m_y;
        public MyPoint1(double x, double y)
        {
            m_x = x;
            m_y = y;
        }
        public double x() { return m_x; }
        public double y() { return m_y; }
    }


    // Non-interfaced class...
    class MyPoint2
    {
        public double x { get; set; }
        public double y { get; set; }
    }

    // (2) Create a wrapper (implementing IPoint)
    class PointWrapper : IPoint
    {
        MyPoint2 m_point;
        public PointWrapper(MyPoint2 p)
        {
            m_point = p;
        }

        public double x() { return m_point.x; }
        public double y() { return m_point.y; }
    }

    // (3) Create a generic wrapper using delegates, implementing IPoint
    class DelPointWrapper<Point> : IPoint
    {
        Point m_point;
        get_x<Point> m_gx;
        get_y<Point> m_gy;

        public DelPointWrapper(Point p, get_x<Point> gx, get_y<Point> gy)
        {
            m_point = p;
            m_gx = gx;
            m_gy = gy;
        }

        public double x() { return m_gx(m_point); }
        public double y() { return m_gy(m_point); }

        public void increase()
        {
            //m_x += 0.000001;
            //m_y += 0.000001;
        }

    }

    // (7) define delegates in a static class
    static class Accessor
    {
        public static get_x<MyPoint2> getX = p => p.x;
        public static get_y<MyPoint2> getY = p => p.y;
    }


    // (8,9) use a sort of Traits class
    class Traits : ITraits<MyPoint2>
    {
        public double get_x(MyPoint2 p)
        {
            return p.x;
        }
        public double get_y(MyPoint2 p)
        {
            return p.y;
        }
    }

    class Program
    {
        const int n = 10000000;

        static void Timed<Point>(String header, Point a, Point b) where Point : IPoint
        {
            double d = 0.0;
            Stopwatch st = new Stopwatch();
            st.Start();
            for (int i = 0; i < n; i++)
            {
                d += Algorithm.Distance(a, b);
            }
            st.Stop();
            System.Console.WriteLine(header + " " + d + " " + st.Elapsed.ToString());
            System.Threading.Thread.Sleep(500);

        }

        // Creating the delegates
        static double point_get_x(MyPoint2 p)
        {
            return p.x;
        }
        static double point_get_y(MyPoint2 p)
        {
            return p.y;
        }

        static void Main(string[] args)
        {

            int option = args.Length > 0 ? Int32.Parse(args[0]) : 10;
            System.Console.Write("{0} ", option);

            // Point without interface
            MyPoint2 p1 = new MyPoint2();
            p1.x = 3;
            p1.y = 5;
            MyPoint2 p2 = new MyPoint2();
            p2.x = 6;
            p2.y = 9;

            switch (option)
            {
                case 1:
                    {
                      // Option 1, point with interface
                      MyPoint1 ip1 = new MyPoint1(3, 5);
                      MyPoint1 ip2 = new MyPoint1(6, 9);
                      Timed("Using interface", ip1, ip2);
                    } break;
                case 2:
                    {
                      // Option 2a:
                      PointWrapper pw1 = new PointWrapper(p1);
                      PointWrapper pw2 = new PointWrapper(p2);
                      Timed("Using wrapper", pw1, pw2);
                    } break;
                case 3:
                    {
                      // Option 2b:
                      DelPointWrapper<MyPoint2> dpw1 = new DelPointWrapper<MyPoint2>(p1, point_get_x, point_get_y);
                      DelPointWrapper<MyPoint2> dpw2 = new DelPointWrapper<MyPoint2>(p2, point_get_x, point_get_y);
                      Timed("Using delegate-wrapper", dpw1, dpw2);
                    } break;
                case 4:
                    {
                      // Option 2c: with inline delegates
                      DelPointWrapper<MyPoint2> idpw1 = new DelPointWrapper<MyPoint2>(p1
                      , delegate(MyPoint2 p) { return p.x; }
                      , delegate(MyPoint2 p) { return p.y; }
                      );
                      DelPointWrapper<MyPoint2> idpw2 = new DelPointWrapper<MyPoint2>(p2
                      , delegate(MyPoint2 p) { return p.x; }
                      , delegate(MyPoint2 p) { return p.y; }
                      );
                      Timed("Using inline delegate-wrapper", idpw1, idpw2);
                    } break;
                case 5:
                    {
                      DelPointWrapper<MyPoint2> ldpw1 = new DelPointWrapper<MyPoint2>(p1, p => p.x, p => p.y);
                      DelPointWrapper<MyPoint2> ldpw2 = new DelPointWrapper<MyPoint2>(p2, p => p.x, p => p.y);
                      Timed("Using lambda-wrapper", ldpw1, ldpw2);
                    } break;
                case 6:
                    {
                      double d = 0.0;
                      Stopwatch st = new Stopwatch();
                      st.Start();
                      for (int i = 0; i < n; i++)
                      {
                      d += Algorithm.Distance(p1, p2, p => p.x, p => p.y);
                      }
                      st.Stop();
                      System.Console.WriteLine("Using delegate-algorithm+lambda " + d + " " + st.Elapsed.ToString());
                    } break;
                case 7:
                    {
                      double d = 0.0;
                      Stopwatch st = new Stopwatch();
                      st.Start();
                      for (int i = 0; i < n; i++)
                      {
                      d += Algorithm.Distance(p1, p2, Accessor.getX, Accessor.getY);
                      }
                      st.Stop();
                      System.Console.WriteLine("Using accessor met static delegates " + d + " " + st.Elapsed.ToString());
                    } break;
                case 8:
                    {
                      Traits traits = new Traits();

                      double d = 0.0;
                      Stopwatch st = new Stopwatch();
                      st.Start();
                      for (int i = 0; i < n; i++)
                      {
                      d += Algorithm.Distance(p1, p2, traits);
                      }
                      st.Stop();
                      System.Console.WriteLine("Using traits " + d + " " + st.Elapsed.ToString());
                    } break;
                case 9:
                    {
                      Traits traits = new Traits();
                      TraitsRegister.Register<MyPoint2>(traits);

                      double d = 0.0;
                      Stopwatch st = new Stopwatch();
                      st.Start();
                      for (int i = 0; i < n; i++)
                      {
                      d += Algorithm.DistanceTR(p1, p2);
                      }
                      st.Stop();
                      System.Console.WriteLine("Using traits/register " + d + " " + st.Elapsed.ToString());
                    } break;
                case 10:
                    {
                      LambdaRegister.Register<MyPoint2>(p => p.x, p => p.y);

                      double d = 0.0;
                      Stopwatch st = new Stopwatch();
                      st.Start();
                      for (int i = 0; i < n; i++)
                      {
                      d += Algorithm.DistanceLR(p1, p2);
                      }
                      st.Stop();
                      System.Console.WriteLine("Using lamba/register " + d + " " + st.Elapsed.ToString());
                    } break;
            }

            System.Console.WriteLine("");
        }
    }
}

And here are the complete timings (for each the smallest of 5 runs):
1 Using interface 50000000 00:00:00.1000114
2 Using wrapper 50000000 00:00:00.1055539
3 Using delegate-wrapper 50000000 00:00:00.1812642
4 Using inline delegate-wrapper 50000000 00:00:00.1843941
5 Using lambda-wrapper 50000000 00:00:00.1810666
6 Using delegate-algorithm+lambda 50000000 00:00:00.1509385
7 Using accessor met static delegates 50000000 00:00:00.1274787
8 Using traits 50000000 00:00:00.1327729
9 Using traits/register 50000000 00:00:00.4192440
10 Using lamba/register 50000000 00:00:00.4194542

Conclusions

Are already done. Specializations in C# are possible. Use them, it makes C# and generics more fun.

Sunday, July 25, 2010

C# Specializations by Traits III


C# Specializations by Traits III


Stormy: Specializations by Traits - Object Relational Model

I like SOCI very much. It is a C++ ORM. Especially the way to go from SQL to model, the object-relational mapping, is very convenient. It is based on specializations.

In the earlier Blogs of this series I have shown that it is possible to do real specializations in C#. This is possible using the combination of traits, a dictionary, and (if necessary) extension methods. This is all explained in previous blogs and I will not explain it again. I will only show how this system is really convenient in Object Relational Mapping (ORM). A hundred-lines prototype is developed. Called Stormy (storm was already occupied).

Use case

In ORM the database (relational) is mapped to objects (models, C# classes). So by nature there are many classes all handled the same way (from SQL to the class instance).

Instead of using the ADO.NET SqlDataReader (delivering just abstract fields and not a model), we want to do things like this:
IEnumerable<Cat> cats = connection.Select<Cat>("select * from cat");

where
  • Cat is our model, shown below
  • connection is any connection to a database
  • the SQL statement is shown, literally. I like that.
  • so it returns a generic collection of our model
In C# it is not trivial to specialize the Select method per model. But with traits and a register it can be solved.

The model Cat

The model Cat is borrowed from nHibernate (I know nHibernate - it will not map the class below - it wants method to be virtual). Slightly modified (I like this way of specifying attributes):

public class Cat
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public char Sex { get; set; }
    public float Weight { get; set; }
}

The Object Relational mapping

The ORM is done entirely in code, the way SOCI does it. No XML mappings here. We stay with C#. We show here the implementations Map the Cat from (relational) Database to Object, and vice versa.


public class CatConverter : ITypeConversion<Cat>
{
    public Cat fromSql(SqlDataReader reader)
    {
        Cat cat = new Cat();
        cat.Id = (Guid)reader["CatId"];
        cat.Name = (string)reader["name"];
        cat.Sex = (((string)reader["sex"]) + " ")[0];
        cat.Weight = (float)reader["weight"];
        return cat;
    }

    public void fillParameters(Cat cat, SqlCommand command)
    {
        command.Parameters.Add(new SqlParameter("@name", cat.Name));
        command.Parameters.Add(new SqlParameter("@sex", cat.Sex));
        command.Parameters.Add(new SqlParameter("@weight", cat.Weight));
    }
}


Note that it is mapped using SqlDataReader. It can be made more convenient (eliminating casts) of course, but this is how it is done with SqlDataReader, normally.

That SOCI-like type-converter (I renamed the methods from_base to fromSQL and to_base to fillParameters) is an interface ITypeConversion<T>, and is registered (normally) once per model:
Orm.Register<Cat>(new CatConverter());


Main program

We can implement our scenario, converting from database to Cat and vice versa, using generic programming. Our program:
class Program
{
    static void Main(string[] args)
    {
        Orm.Register<Cat>(new CatConverter());

        Connection connection = new Connection(
            @"
                Data Source=localhost\SQLEXPRESS;
                MultipleActiveResultSets=True;
                Initial Catalog=stormy;
                Integrated Security=SSPI;
            "
);

        var cats = connection.Select<Cat>("select * from cat");
        foreach(Cat cat in cats)
        {
            System.Console.WriteLine("Cat {0} named {1}", cat.Id, cat.Name);
        }

        // Create subselection using linq (not related to SpecializationbyTraits)
        var toms = from cat in cats where cat.Name == "Tom" select cat;
        if (toms.Count() > 0)
        {
            Cat tom = toms.First();
            System.Console.WriteLine("Tom found, ID={0}", tom.Id);
        }
        else
        {
            Cat tom = new Cat();
            tom.Name = "Tom";
            tom.Sex = 'm';
            tom.Weight = 5.2F;
            connection.Execute(CatConverter.InsertSql(), tom);
        }
    }
}


We first register our type conversion specialization. We create a connection to the database (hard coded - alternatively you might get it from e.g. appSettings). We can use any SQL statement to fill any list with any (registered) model. For fun we use LINQ here to do a subselection. We can execute SQL to insert, update or delete things. That InsertSql is specified (for convenience, I prefer it close to its parameters) within the converter as well, it can be anywhere, up to you.
public static string InsertSql()
{
    return "insert into Cat(CatId, Name, Sex, Weight) values(NEWID(), @name, @sex, @weight)";
}



Stormy ORM - wrapping it up


Great isn't it? The Stormy code is about hundred lines now. Of course it is not a full-featured ORM as others are, but in many cases more convenient, more simple to understand, it does not create shadow classes, and it does not force you to learn a new criteria language. If you know SQL, you will like it!

The project including sample can be downloaded here.

We're nearly done with C# Specializations. It is really useful. Can be used everywhere. Makes C# closer to C++.

Next:
Stay tuned!