Friday, January 14, 2011

Enum subsets in C#

After a few years of working with Haskell I've become nearly obsessed with expressing constraints in the type system. Although the C# type system isn't as expressive as Haskell's, preconditions, postconditions, ranges, complexity, and other things can be expressed. If the type is expressive enough then you don't even have to do any validation or checking when working with it because the compiler already guaranteed that the data is valid. One of the problems with C# enums is that they aren't real objects so they can't subclass; they're just pretty wrappers around primitives like ints or bytes. This means that if you only allow certain values of an enum then you have to manually check at runtime:

public void DeclareDayIsSpecial(DayOfWeek day)
{
  if (day == DayOfWeek.Sunday || day == DayOfWeek.Saturday)
    throw new ArgumentException("When declaring that a day is special, the day must be a weekday.", "day");
 
  Console.WriteLine("{0} is special.", day);
}

Even though you can't define an enum as a subclass of another and allow only that subclass, you can define an enum as subset of another.

public enum Weekday
{
   Monday = DayOfWeek.Monday,
   Tuesday = DayOfWeek.Tuesday,
   Wednesday = DayOfWeek.Wednesday,
   Thursday = DayOfWeek.Thursday,
   Friday = DayOfWeek.Friday,
}

Once you have this you can constrain your methods to just the valid subset of values.

public void DeclareDayIsSpecial(Weekday weekday)
{
  Console.WriteLine("{0} is special.", weekday);
}

The compiler won't allow you to use an invalid value so you have compile time documentation and feedback and can remove the runtime checks. This can be useful if you use enums in a scenario where only some values are valid. And since enums are wrappers around primitive types, you can safely cast from the subset (Weekday) to the superset (DayOfWeek).

Thursday, January 6, 2011

Programming and a theory of mind

A couple days ago I realized that programming is by far the most social thing I do. Sure, I discuss things with other developers, QA, and business analysts, but that's a small part of my time. The vast majority of my time is spent looking at what is already there and trying to understand it. Not just what it does or how it does it, but why. And this requires a Theory Of Mind.

A theory of mind is when you realize that other people have their own mind and their own ideas that are separate and different from yours. Everything I see at work isn't some naturally occurring thing - it was created by someone, it has an intended purpose, a reason for being, some business or technical need that it meets. Much of my time is spent interacting with others but only when programming do I need to look into so many other minds at the same time, to find and understand the intent of the original developer, the business scenario being addressed, the reasons why it was done this way and not that way, and why it's still being done this way. Writing code generally isn't difficult, especially business apps, it's understanding the intent and reasons for the code that's tough. Like it says in Structure and Interpretation of Computer Programs, "Programs should be written for people to read, and only incidentally for machines to execute."

Wednesday, December 29, 2010

An algorithm to find floating holidays

I've always liked dealing with code that works with dates and times. You learn a lot about our calendars and all the hacks to make up for our inaccurate decisions hundreds of years ago and for the earth's wobbles and year-to-year inconsistencies.

One task that's come up again and again is determining floating holidays. Here's a very quick and easy way I discovered to determine floating days (every 4th thursday etc) and fixed days that are observed on friday or monday when the day is a holiday.

All you need is a list or array of the 7 days of the month it falls on. The first element is the day of the month the holiday is on when the month begins on a Sunday, the second element is the day of the month the holiday is on when the month begins on a Monday, and so on. Once you find what day of the week the month starts on, you can just lookup the day you're looking for. So you know the year, the month, and the day the holiday falls on for any year of that calendar.

For example, American Independence day is celebrated on the 4th of July or the closest weekday when it falls on a weekend. Using a calendar we can see that the days of the month are [4,4,4,3,5,4,4], i.e. when July starts on a Wednesday (4th element in the list) the holiday is celebrated on the 3rd, when it starts on a Thursday (5th element in the list) the holiday is celebrated on the 5th, otherwise it's celebrated on the 4th. American Thanksgiving day is celebrated on the 4th Thursday of November so the days of the month are [26,25,24,23,22,21,27], i.e. when November starts on a Sunday the holiday is celebrated on the 26th, when November starts on a Monday the holiday is celebrated on the 25th, etc.

The java is much less verbose than the english description:


public Calendar getAmericanIndependanceDay(int year){
        return getFloatingDay(year, 6, new int[]{4,4,4,3,5,4,4});
    }

    public Calendar getAmericanThanksgivingDay(int year){
        return getFloatingDay(year, 10, new int[]{26,25,24,23,22,21,27});
    }

    private Calendar getFloatingDay(int year, int month, int[] days){
        Calendar firstDayOfTheMonth = new GregorianCalendar(year, month, 1);
        int firstDayOfTheWeek = firstDayOfTheMonth.get(Calendar.DAY_OF_WEEK) - 1;
        return new GregorianCalendar(year, month, days[firstDayOfTheWeek]);
    }

Thursday, December 23, 2010

Unit tests are not inherently good

Unit tests cause pain. Unit tests, by themselves, do not solve problems, do not make users happy, do not make maintainers happy, do not make a better product, and do not improve design. Unit tests make certain things hurt; nothing more and nothing less. But pain can indicate something is wrong and can lead you to do something else.

The first assumption behind unit tests (and bodily pain) is that if something hurts we'll pay attention and do something else instead. The second assumption is that what we do as an alternative will not only hurt less but make things better. For example, since unit tests make singletons and hard coded dependancies so painful, we can rely on dependency injection techniques and the single responsibility principal. This should cause code that is easier to test and understand and that responds to rapidly changing requirements.

So unit tests are one way to show what hurts and needs attention and avoid blundering into bad and potentially project-killing designs. The problem is when we can't or don't change how things are done. If we must rely on singletons, the filesystem, database, complex api calls, undefined behavior, or slow techniques then writing and running the unit tests will hurt. In these cases the costs of writing and maintaing unit tests can outweigh the benefits of running those tests.

Wednesday, December 8, 2010

Announcing AsciiPanel

I recently created a git repository for AsciiPanel, a java control that simulates a code page 437 ASCII terminal display. It supports all 256 characters of codepage 437, arbitrary foreground colors, arbitrary background colors, and arbitrary terminal sizes.

This is an example mini-rougelike that uses an AsciiPanel.




AsciiPanel, jar file or source, can be found at https://github.com/trystan/AsciiPanel.

[edit] The test applet seems to be missing. [/edit]