Posts

Roles in C# Implementation

After seeing what roles in C# might look like, let's see the necessary transformations that would enable them. This is one possibility that a C# compiler could use to implement roles without having to make changes to the underlying CLR. Roles A role is transformed into a set of types: an interface (which the compositions will implement), a static class with the role code, and a class that encapsulates the role state. The interface for the role is the most important type and it will carry the role name. Because all the generated types are related, they'll be packaged together as nested types inside the role interface. Nesting types inside an interface is not supported in C#, but is supported by the underlying CIL. So we'll be looking at some invalid C# along the way; just think of it as "decompiled" CIL. Let's see these transformations for a simple role: role RPrintableWithCount { int count = 0; public void Print() { Console.WriteLine(...

Roles in C#

Traits (pdf) are described as composable units of behavior, and are a natural evolutionary path for languages like C# or Java. Microsoft must be seriously looking at them, since it's sponsored some research about Traits in C# (pdf) . I'll describe what I think is an extension to the traits idea that would make a great feature in C# (and in Java, VB.NET, ...): roles. Roles are already a reality in Perl 5, with the Moose::Roles module. They even have their own syntax in Perl 6 . They help create better organized and reusable code, are an effective and safer alternative to multiple inheritance, and have explicit semantics (which means no surprises) as opposed to mixins. What I'll describe here is based on the theoretical traits (as described in the traits paper), on Perl roles and on Scala traits , all adapted to C#. A role is, like a class, a type that holds behavior and state. It can be composed into a type (either a class, a struct or another role) to make its memb...

Working Effectively with Legacy Code

Image
It's a known fact of life that code bases, if not actively nurtured, deteriorate with time. Maintaining, fixing bugs, extending, creating new features; all exert forces that push a design beyond its original intended boundaries, breaking the envelope of its original frame. Not long after its first release (sometimes, even before it), there's not even a trace of design, there's no conceptual integrity; duplication and needless complexity abound. Understanding and changing such systems is very difficult, technical debt never seems to decline. No position is more dreaded than that of the maintenance programmer. It's certainly not fun to work in these big balls of mud . Debugging sessions can take days, every time a change is required, there's fear that some unrelated functionality might suddenly break. In the book Working Effectively with Legacy Code , author Michael Feathers gives wonderful advice and practical, to-the-point techniques to deal with these quagmi...

A more understandable IComparable

"Any fool can write code that a computer can understand. Good programmers write code that humans can understand." - Martin Fowler In the .NET framework the IComparable<T> interface is used to compare values: public interface IComparable<T> { int CompareTo(T other); } The comparison is done with the CompareTo method. It returns zero if the current object is equal to the passed in parameter; a negative number if it's less than the parameter; and a positive number if it's greater than it. That's a very non-intuitive return value, reminiscent of the C strcmp function. I know that this scheme is already ingrained in our brains, but it creates code that's not directly decipherable: static int BinarySearch<T>(IList<T> list, T target) where T : IComparable<T> { if (list == null) throw new ArgumentNullException("list"); int lower = 0; int upper = list.Count - 1; while (lower <= upper) { int midd...

Scala Traits Under the Hood

Scala is a very feature-rich language built on top of the JVM (there's also a version on the CLR , but the focus is clearly on the JVM). Besides its functional features, it introduces a number of constructs that facilitate large scale components development and code reuse. Scala has traits, which are a great tool for orthogonal code reuse. In its simplest form, a trait can be used just like an interface, with only abstract members, defining a contract that derived types must fulfill. It can also have concrete members, including properties and fields. Classes (and traits) can inherit from multiple traits ("inherit" is the wrong term here, better ones are "use" or "mix in"), and gain all their capabilities. Traits enable a kind of composition that doesn't rely on the structure imposed by a multiple inheritance relationship. It's more suitable for combining a target class with the roles that it performs, which should not be part of its inhe...

C# Quasi-Mixins Example

As an example, I'll adapt one of the mixins found in the book Fundamentals of Object-Oriented Design in UML to use the C# quasi-mixins pattern . Given the following (simplified) domain classes: namespace Domain { public enum Medium { Email, SnailMail, IntergalacticMail } public class Customer { public string Name { get; set; } public string Address { get; set; } public string Email { get; set; } public Medium PreferredMedium { get; set; } } public class Invoice { public string Header { get; set; } public List<string> LineItems { get; set; } public Customer Customer { get; set; } } } We'd like to be able to send an invoice to a customer by using his preferred medium. To keep the code to send the invoice separate from the Invoice domain class, and to abstract it so that it can send any kind of document (not just invoices) that adhere to a certain format, a mixin to send documents is created: namespace ...

C# Quasi-Mixins Pattern

Extension methods are an interesting feature of C#. They allow for behavior to be added to existing classes. For example, a ToXml() method can be added to class Object , effectively making that method available everywhere: public static class XmlSerializableExtension { public static string ToXml(this Object self) { if (self == null) throw new ArgumentNullException(); var serializer = new XmlSerializer(self.GetType()); using (var writer = new StringWriter()) { serializer.Serialize(writer, self); return writer.GetStringBuilder().ToString(); } } // for completeness... public static T FromXml<T>(string xml) { var serializer = new XmlSerializer(typeof(T)); return (T)serializer.Deserialize(new StringReader(xml)); } } So, any instance can be serialized to XML simply like this: var customer = new Customer { Name = "Guybrush Threepwood", Preferred = true }; var xml = customer.ToXml(); Now, certainly all classes ...