Monday, July 7, 2008

Method Hiding - Feature or Bug in Compiler?

Since its very beginning C# has a 'method hiding' feature, which lets us 'hide' base class non-virtual methods. In other words one can write:
class Base
{
public void Test() {
Console.WriteLine("Base");
}
}

class Derived : Base
{
public new void Test() {
Console.WriteLine("Derived");
}
}

//...

Derived d = new Derived();
d.Test(); // "Derived" is printed


So far so good, but what happens if I write:



Base d = new Derived();
d.Test(); // "Base" is printed


Is this an intended behavior? Well, may be yes, but may be no. In case of 'no', we just called a wrong function, and no warning or error was issued by the compiler... Just consider again what happened, we declared a non-virtual method - that's our contract that should be ensured by the compiler. Instead it provides us with a feature to break it.



That's not all, consider the situation where you have some 3rd party library and use it in your project. Now the vendor releases a new version where he hides some method and provides an alternative implementation. Your program will still call the old method until you recompile! So in case you have several modules some recompiled and some not, you may have inconsistent behavior...



Of course you can always find use-cases, where the feature is carefully used and actually is very useful in that context. Yet its disadvantages outweight the advantages, so I think it would be better if we will develop our programs without using it.



Unfortunately there is an additional very similar "feature" - private interfaces, which can be implemented by a type even if its base class already implemented it and declared it sealed. Again the language helps us to break the contract and if it's not done carefully enough, the bugs won't wait to come...

Friday, July 4, 2008

C# Co[ntra]variance

To get introduced to the topic, please read Eric Lippert's variance series first.

Here I would like to present my solution to the problem.

After all there are only 3 possibilites:

  1. Clear covariance (IEnumerator<T>).
  2. Clear contravariance (IComparer<T>).
  3. Undecidable (IList<T>).

All the 3 possibility are easily detectable by compiler and I believe for the first two we would like the compiler will decide the variance automatically. We need a solution for the third case only.

To see the solution, I would like first analyze how we selected which case the given interface belongs to. We analyzed the method signatures in which T is involved:

  1. If in all of them T is 'out' parameter, the interface is covariant.
  2. If in all of them T is 'in' parameter, the interface is contravariant.
  3. If there is a mix - undecidable.

My solution is to say the compiler how I'm going to use my variable and enable either covariant or contravariant invocations:

IList<Animal> aa = whatever;
IList<in Giraffe> ag = aa;
IList<out Giraffe> agX = aa; //fails to compile

ag user sees: 'int ag.IndexOf(Giraffe)' and 'object ag[int]'.

IList<Giraffe> ag = whatever;
IList<out Animal> aa = ag;
IList<in Animal> aaX = ag; //fails to compile

aa user sees: 'int aa.IndexOf(<only null can be passed>)' and 'Animal aa[int]'.

Now I can say in a type safe manner:



class X<T> {

T _t;

void Test(IList<out T> at) {
T t = at[0]; //clearly t is 'out' parameter
}

void Test(IList<in T> at) { //overloaded method!
int i = at.IndexOf(_t); //clearly _t is 'in' parameter
}
}

//...

new X<Animal>().Test(new List<Giraffe>()); //first method is called
new X<Giraffe>().Test(new List<Animal>()); //second method is called

Monday, June 16, 2008

Domain Specific Language (DSL) with Workflow, Part 2

In the previous article I presented some basic ideas for creating DSL activities in Workflow. In this part I want to deep into the challenges I faced during the implementation and share the solutions. As usual, let's start from the requirements:

  1. DSL is a set of services, each one implemented by a separate function.
  2. For each such function provide a specialized Activity.
  3. All the return/out/ref parameters should work as expected.
  4. Developing of those Activities should be simple and provide Activity validation.

The first requirement is easy - I can have a separate method for each DSL service in my ExternalDataExchange interface:

// The ExternalDataExchange attribute is a required attribute 
// indicating that the local service participates in data exchange with a workflow
[ExternalDataExchange]
public interface ITaskService
{
int CreateTask(string taskId, string assignee, ref string text);

//...
}


To meet the next requirements I wanted to provide a base class, that by simple derivation from it and decorating my properties with some attribute, the desired DSL activity will be created:



[ToolboxItemAttribute(typeof(ActivityToolboxItem))]
public class CreateTask : DslActivity<CreateTask>
{
// Properties on the task
public static readonly DependencyProperty ReturnValueProperty = DependencyProperty.Register("ReturnValue", typeof(System.Int32), typeof(CreateTask));
public static readonly DependencyProperty AssigneeProperty = DependencyProperty.Register("Assignee", typeof(System.String), typeof(CreateTask));
public static readonly DependencyProperty TaskIdProperty = DependencyProperty.Register("TaskId", typeof(System.String), typeof(CreateTask));
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(System.String), typeof(CreateTask));

public CreateTask()
// Map the activity to the service method
: base(typeof(ITaskService), "CreateTask")
{
}

// Property, mapped to the return value of the method
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
[BrowsableAttribute(true)]
// "Well Known" name for the return value
[DslParameter(Name = "(ReturnValue)")]
[Category("ReturnValue")]
public int ReturnValue
{
get
{
return ((int)(base.GetValue(ReturnValueProperty)));
}
set
{
base.SetValue(ReturnValueProperty, value);
}
}

// Property, mapped to the 'assignee' parameter of the method
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
[BrowsableAttribute(true)]
[DslParameter(Name = "assignee")]
[Category("Parameters")]
public string Assignee
{
get
{
return ((string)(base.GetValue(AssigneeProperty)));
}
set
{
base.SetValue(AssigneeProperty, value);
}
}

// Other properties - mappings to the rest method parameters


In this way development of DSL activities is simple and straightforward. Now let's look into the base class to see how it's achieved. All the magic is done inside the constructor:



// Initializes parameters by reflecting the typeof(T) members
// and looking for DslParameterAttribute attribute.
private static readonly IList<ParameterInfo> _parameters = GetParameters(typeof(T));

public DslActivity(Type interfaceType, string methodName)
{
// Set up the interface and method
InterfaceType = interfaceType;
MethodName = methodName;

for (int i = 0; i < _parameters.Count; i++)
{
ParameterInfo pi = _parameters[i];
// This is the main 'trick' - create a binding to 'this' Activity
// with path set to the relevant property name
ActivityBind bind = new ActivityBind("/Self", pi.Path);
WorkflowParameterBinding binding = new WorkflowParameterBinding(pi.ParameterName);
binding.SetBinding(WorkflowParameterBinding.ValueProperty, bind);
ParameterBindings.Add(binding);
}
}


That's all, hope you enjoyed! Download here the sample code for this article.