Singleton types vs. instances as type parameters

Oh yes, this question :slight_smile:. Fond memories. In JuliaDiffEq, we had a similar problem: what should

solve(prob,alg)

dispatch on, the type of alg or its instance? We had a month where we:

  1. Went with the type
  2. Went to the instance
  3. Went back to the type
  4. Finally at the instance.

It has stayed with the instance ever sense. Example:

solve(prob,RK4())

The reason is because this is much more flexible. It took me awhile to get here though! Arguments are given here:

The general idea is that, if you’re using the instance, you have the full power of the constructor. It is strictly more powerful while the syntax isn’t much more. Some examples are:

  1. Defaults in the constructor. You might create a whole family of related types for dispatch using a type parameter. I see Variable{:x}. What if you wanted a default variable? Using an instance, you can easily make a default constructor that throws :x in there. If you go with the type, you cannot do such defaults later.

  2. If you want some kinds of relations between the types and values in the parameters, you can enforce that with a constructor.

  3. You can add details (more parameters) without breaking code. If you suddenly need a second parameter, say some number which is normally 1 but 2 is some cool new feature, codes which use Variable{:x} will break when you go to Variable{:x,1}, but again a constructor can handle this by putting a default in there.

  4. You never know if you’ll need fields! You have the option to use them in the future if you use instances, even if it’s just for storing some constants.

There’s probably a bit more too, but that’s the general idea. The flexibility is helpful in the long run.

12 Likes