Design alternatives to extending object with interface

f#

Solution

I think the problem that you're trying to solve here is what is called The Expression Problem. You're essentially trying to write code that would be extensible in two directions. Discriminated unions and object-oriented model give you one or the other:

Discriminated union makes it easy to add new operations (just write a function with pattern matching), but it is hard to add a new kind of expression (you have to extend the DU and modify all code that uses it).

Interfaces make it easy to add new kinds of expressions (just implement the interface), but it is hard to add new operations (you have to modify the interface and change all code that creates it.

In general, I don't think it is all that useful to try to come up with solutions that let you do both (they end up being terribly complicated), so my advice is to pick the one that you'll need more often.

Going back to your problem, I'd probably represent the function just as a function name together with the parameters:

type Expr =
  | Num of decimal
  | Var of string
  | Application of string * Expr list

Really - an expression is just this. The fact that you can take derivatives is another part of the problem you're solving. Now, to make the derivative extensible, you can just keep a dictionary of the derivatives:

 let derrivatives = 
   dict [ "sin", (fun [arg] -> Application("cos", [arg])) 
          ... ] 

This way, you have an `Expr` type that really models just what an expression is and you can write differentiation function that will look for the derivatives in the dictionary.

Problem

While working through Expert F# again, I decided to implement the application for manipulating algebraic expressions. This went well and now I've decided as a next exercise to expand on that by building a more advanced application. My first idea was to have a setup that allows for a more extendible way of creating functions without having to recompile. To that end I have something like: ``` type IFunction = member x.Name : string with get /// additional members omitted type Expr = | Num of decimal | Var of string ///... omitting some types here that don't matter | FunctionApplication of IFunction * Expr list ``` So that say a Sin(x) could be represented a: ``` let sin = { new IFunction() with member x.Name = "SIN" } let sinExpr = FunctionApplication(sin,Var("x")) ``` So far all good, but the next idea that I would like to implement is having additional interfaces to represent function of properties. E.g. ``` type IDifferentiable = member Derivative : int -> IFunction // Get the derivative w.r.t a variable index ``` One of the ideas the things I'm trying to achieve here is that I implement some functions and all the logic for them and then move on to the next part of the logic I would like to implement. However, as it currently stands, that means that with every interface I add, I have to revisit all the IFunctions that I've implemented. Instead, I'd rather have a function: ``` let makeDifferentiable (f : IFunction) (deriv : int -> IFunction) = { f with interface IDifferentiable with member x.Derivative = deriv } ``` but as discussed in this question, that is not possible. The alternative that is possible, doesn't meet my extensibility requirement. My question is what alternatives would work well? [EDIT] I was asked to expand on the "doesn't meet my extenibility requirement" comment. The way this function would work is by doing something like: ``` let makeDifferentiable (deriv : int -> IFunction) (f : IFunction)= { new IFunction with member x.Name = f.Name interface IDifferentiable with member x.Derivative = deriv } ``` However, ideally I would keep on adding additional interfaces to an object as I add them. So if I now wanted to add an interface that tell whether on function is even: ``` type IsEven = abstract member IsEven : bool with get ``` then I would like to be able to (but not obliged, as in, if I don't make this change everything should still compile) to change my definition of a sine from ``` let sin = { new IFunction with ... } >> (makeDifferentiable ...) ``` to ``` let sin = { new IFunction with ... } >> (makeDifferentiable ...) >> (makeEven false) ``` The result of which would be that I could create an object that implements the IFunction interface as well as potentially, but not necessarily a lot of different other interfaces as well; the operations I'd then define on them, would potentially be able to optimize what they are doing based on whether or not a certain function implements an interface. This will also allow me to add additional features/interfaces/operations first without having to change the functions I've defined (though they wouldn't take advantage of the additional features, things wouldn't be broken either.[/EDIT] The only thing I can think of right now is to create a dictionary for each feature that I'd like to implement, with function names as keys and the details to build an interface on the fly, e.g. along the lines: ``` let derivative (f : IFunction) = match derivativeDictionary.TryGetValue(f.Name) with | false, _ -> None | true, d -> d.Derivative ``` This would require me to create one such function per feature that I add in addition to one dictionary per feature. Especially if implemented asynchronously with agents, this might be not that slow, but it still feels a little clunky.

Original source