Showing posts with label dynamicity. Show all posts
Showing posts with label dynamicity. Show all posts

Saturday, January 16, 2010

C# dynamic types and the design patterns.

NOTES
This post is resurrected. I accidentally deleted this earlier.

Preface
The question that gives me no rest lately is how I can use C# 4.0 dynamic features in the real-world .NET applications. For a long time I had no ideas except of using dynamic objects in LINQ queries. It is briefly discussed in the comments to C# 4.0 - the first look at the DYNAMICITY post. But today I know another answer and it seems to be breathtaking. The answer is we don't need to use the OOP design patterns if we have the support of the "Dynamicity Forces".

Design patterns
Design patterns are part of the fundamental of Object Oriented Programming. Tremendous amount of resources have appeared on design patterns after the book Design Patterns: Elements of Reusable Object-Oriented Software was published in 1994. Each person involved in OOP programming was learning the design patterns. I used to use the design patterns in my every-day-work. Design patterns typically show relationships and interactions between classes or objects, without specifying the final application classes or objects that are involved. Technically that means that the type of the object which is passed to be handled by the application isn't known at compile time. Design patterns use the objects inheritance, composition, etc. to effectively solve the problem then the final object type isn't known at compile time. But wait...now we have the C# dynamic types which is intended to be used when the type of an object isn't known at compile time! Yes, I assert that any well-known design pattern can be avoided by using the dynamic types. Let me show the example.

Bridge design pattern(classic approach).
Bridge design pattern is very powerful and applies to many situations. Its purpose - "decouple an abstraction from its implementation so that the two can vary independently" - is not possible to understand without the real-world example. The classic example is shown below. I copied the code from the wikipedia article and updated it a bit(C# 3.0 is used).

internal interface IDrawingAPI
{
   void DrawCircle(double x, double y, double radius);
   void DrawLine(double x1, double y1, double x2, double y2);
}

internal class DrawingAPI1 : IDrawingAPI
{
   public void DrawCircle(double x, double y, double radius)
   {
      Console.WriteLine("API1.circle at {0}:{1} radius {2}", x, y, radius);
   }
   public void DrawLine(double x1, double y1, double x2, double y2)
   {
      Console.WriteLine("API1.line from {0},{1} to {2},{3}", x1, y1, x2, y2);
   }
}

internal class DrawingAPI2 : IDrawingAPI
{
   public void DrawCircle(double x, double y, double radius)
   {
      Console.WriteLine("API2.circle at {0}:{1} radius {2}", x, y, radius);
   }
   public void DrawLine(double x1, double y1, double x2, double y2)
   {
      Console.WriteLine("API2.line from {0},{1} to {2},{3}", x1, y1, x2, y2);
   }
}

internal interface IShape
{
   void Draw();
}

internal sealed class LineShape : IShape
{
   public double X1 { get; set; }
   public double X2 { get; set; }
   public double Y1 { get; set; }
   public double Y2 { get; set; }
   public IDrawingAPI DrawingAPI { get; set; }
   public void Draw()
   {
      DrawingAPI.DrawLine(X1, Y1, X2, Y2);
   }
}

internal class CircleShape : IShape
{
   public IDrawingAPI DrawingAPI{ get; set;}
   public double X{ get; set;}
   public double Y{ get; set;}
   public double Radius{ get; set;}
   public void Draw()
   {
      DrawingAPI.DrawCircle(X, Y, Radius);
   }
}

internal class BridgePatternClient
{
   public static void Main(string[] args)
   {
      var shapes = new IShape[2];
      shapes[0] = new CircleShape {X = 1, Y = 2, Radius = 3, DrawingAPI = new DrawingAPI1()};
      shapes[1] = new LineShape {X1 = 1, Y1 = 2, X2 = 3, Y2 = 4, DrawingAPI = new DrawingAPI2()};
      foreach (IShape shape in shapes)
      {
         shape.Draw();
      }
   }
}

In this example bridge design pattern is used to decouple the shape abstraction from the drawing implementation. Indeed there are alternate ways to design such a system, but these ways have the important design flaws. This is greatly described in Design Patterns Explained: A New Perspective on Object-Oriented Design book(must read!). Now let me show how I can accomplish the same task as shown above by using dynamic types.


Dynamicity in action.
The code that shown below is written in Visual Studio 2010 and it works fine. It's so simple that doesn't need to be explained. Just look at this.

internal sealed class DrawingAPI1
{
   public void DrawCircle(double x, double y, double radius)
   {
      Console.WriteLine("API1.circle at {0}:{1} radius {2}", x, y, radius);
   }
   public void DrawLine(double x1, double y1, double x2, double y2 )
   {
      Console.WriteLine("API1.line from {0},{1} to {2},{3}", x1, y1, x2, y2);
   }
}

internal sealed class DrawingAPI2
{
   public void DrawCircle(double x, double y, double radius)
   {
      Console.WriteLine("API2.circle at {0}:{1} radius {2}", x, y, radius);
   }
   public void DrawLine(double x1, double y1, double x2, double y2)
   {
      Console.WriteLine("API2.line from {0},{1} to {2},{3}", x1, y1, x2, y2);
   }
}

internal sealed class Line
{
   public double X1 { get; set; }
   public double X2 { get; set; }
   public double Y1 { get; set; }
   public double Y2 { get; set; }
   public dynamic DrawingAPI { get; set; }
   public void Draw()
   {
      DrawingAPI.DrawLine(X1, Y1, X2, Y2);
   }
   }

internal sealed class Circle
{
   public double X { get; set; }
   public double Y { get; set; }
   public double Radius { get; set; }
   public dynamic DrawingAPI { get; set; }
   public void Draw()
   {
      DrawingAPI.DrawCircle(X, Y, Radius);
   }
}

public class Program
{
   [STAThread]
   static void Main()
   {
      DrawingAPI1 api1 = new DrawingAPI1();
      DrawingAPI2 api2 = new DrawingAPI2();
      dynamic[] shapes = { new Line { X1 = 1, Y1 = 1, X2 = 2, Y2 = 3, DrawingAPI = api1 },
               new Circle { X = 10, Y = 20, Radius = 40.4f, DrawingAPI = api2 }
      };
      foreach (dynamic shape in shapes)
      {
         shape.Draw();
      }
   }
}

So, when we don't know the final type of the Shape and Drawing API we use dynamic type. Do you like it?


In conclusion.
This post is about dynamic features of C# of course. But it brings up more general question. In our days the programming technologies changes are incredible. It's good practice to keep up with Changes. But sometimes the changes can make us forgetting the good, old-fashioned technologies. I think that we should be careful with this effect. The new technologies can be awesome, greatly suitable for my needs. The old technologies can also be suitable for the problems I solve. A good problem-solver tries several possible solutions and selects the best one. A good problem-solver doesn't use the technology just because it is cutting-edge.

Saturday, January 24, 2009

C# 4.0 - the first look at the DYNAMICITY.

This week I looked at C# dynamic features that were added in C# 4.0 CTP and Visual Studio 2010. Tremendous amount of resources have appeared on dynamic features of C# over the web. C# developers provided the description of dynamic features on their blogs, i.e. Sam Ng’s blog and Chris Borrows’ blog have the great posts about the topic. However, not all the dynamic features are available in C# 4.0 2008 CTP. I.e. a lot of samples listed in the mentioned blogs don’t event compile in the current VS.NET 2010 preview. So I didn’t dive in the specific language constructions and tricks. What makes me excited is step forward to “dynamicity” in .NET. I never worked with dynamic languages before but apparently it’s about time to learn more about the dynamic languages facilities. Well, I found MSDN magazine article called CLR Inside out: IronPython and read the beautiful thing:

The most common question I hear about dynamic languages is "why should I use them?" Trying to show a longtime C++ or C# developer that a dynamic language is useful for problems outside the scripting domain is difficult. One concrete benefit of dynamic languages is that they facilitate an iterative development cycle. The interactive capabilities of dynamic languages make them a better match for this type of cycle than compiled languages. Developers can focus on exploring and prototyping functionality, refactoring if necessary, and then repeating with new functionality. This allows for a more exploratory process of development than the code/build/run/debug loop that most other languages constrain the programmer to.

So, the dynamic language, well C# 4.0, will allow transition from code/build/run/debug loop to evaluation/print loop? Yes, in PDC 2008 “Future of C#” talk Anders Hejlsberg shows it in action and it looks amazing. The new language features like dynamic type, IDynamicLanguage interface, optional and named parameters also look very promising. Next week I will try to work with C# 4.0 as with dynamic language, I think the best way to do this is get some problem, solve it using C# 3.0(statically typed language), then solve it using C#4.0(dynamic language). I will write about any interesting stuff.