Implementing the virtual method pattern in C#, part three

Last time we saw how you could emulate virtual methods in a language that only had static methods by creating fields of delegate type, and then choosing what delegates go into the fields. However, this is not very space-efficient. Suppose there were a hundred virtual methods on Animal instead of two. That means that every class derived from Animal has a hundred fields, and in most of them, those fields are exactly the same, all the time. You make three hundred giraffes and each one of them will have exactly the same delegates in those hundred fields. This seems redundant and wasteful.

What the CLR actually does is it bundles those up into a virtual function dispatch table, or “vtable” for short. A vtable is a collection of delegates; the purpose of the vtable is to answer the question “if a virtual method was invoked on an object of this runtime type, which method should be called?”

Continue reading

Advertisements

Implementing the virtual method pattern in C#, part two

So far we’ve gotten rid of instance methods; they’re just static methods that take a hidden “this” parameter. But virtual methods are a bit harder. We’re going to implement virtual methods as fields of delegate type containing delegates to static methods.
Continue reading

Implementing the virtual method pattern in C#, part one

If you’ve been in this business for any length of time you’ve undoubtedly seen some of the vast literature on “design patterns” — you know, those standard solutions to common problems with names like “factory” and “observer” and “singleton” and “iterator” and “composite” and “adaptor” and “decorator” and… and so on. It is frequently useful to be able to take advantage of the analysis and design skills of others who have already given considerable thought to codifying patterns that solve common problems. However, I think it is valuable to realize that everything in high-level programming is a design pattern. Some of those patterns are so good, we’ve baked them right into the language so thoroughly that most of us don’t even think of them as examples patterns anymore, patterns like “type” and “function” and “local variable” and “call stack” and “inheritance”.

I was asked recently how virtual methods work “behind the scenes”: how does the CLR know at runtime which derived class method to call when a virtual method is invoked on a variable typed as the base class? Clearly it must have something upon which to make a decision, but how does it do so efficiently? I thought I might explore that question by considering how you might implement the “virtual and instance method pattern” in a language which did not have virtual or instance methods. So, for the rest of this series I am banishing virtual and instance methods from C#. I’m leaving delegates in, but delegates can only be to static methods. Our goal is to take a program written in regular C# and see how it can be transformed into C#-without-instance-methods. Along the way we’ll get some insights into how virtual methods really work behind the scenes.
Continue reading

To box or not to box

Suppose you have an immutable value type that is also disposable. Perhaps it represents some sort of handle.

struct MyHandle : IDisposable
{
  public MyHandle(int handle) : this() { this.Handle = handle; }
  public int Handle { get; private set; }
  public void Dispose() 
  {
    Somehow.Close(this.Handle);
  }
}

You might think hey, you know, I’ll decrease my probability of closing the same handle twice by making the struct mutate itself on disposal!

public void Dispose()
{
  if (this.Handle != 0)
    Somehow.Close(this.Handle);
  this.Handle = 0;
}

This should already be raising red flags in your mind. We’re mutating a value type, which we know is dangerous because value types are copied by value; you’re mutating a variable, and different variables can hold copies of the same value. Mutating one variable does not mutate the others, any more than changing one variable that contains 12 changes every variable in the program that also contains 12. But let’s go with it for now.

What does this do?
Continue reading