Sure, feel free)

That is not what I was trying to say, but it is a plausible way of thinking, at some meta level of thinking. I will return to the code reuse a little bit later. I didn’t have time to write a short answer, so I wrote a long one instead

The idea of modeling is that we’re trying to build a *mathematical* model that suits our needs and represents objects in the universe in some expected way. Than enables mathematical reasoning and proving and verification of certain properties of the *model*. If the PL that we’re using allows it (and OCaml does) then *an implementation* of the model could be verified by the type checker.

When a system is designed the designer creates a model in some high-level specification language (sometimes just natural language), that basically says what entities exist, how do they interact, what properties they exhibit, and how they expected to be used. This model is used to communicate ideas between developers, to devise tests, etc, etc.

The model has nothing to do with the implementation, besides the fact, the implementation should match the specification of the model. This could be verified by testing. In OCaml, it could be also verified statically, to some extent, by the type checker.

Even more, modeling has nothing to do with the code reuse. Your implementation may use copy-pasting, or whatever method to do this. Trying to capture in the model implementation details is a bad idea, that will only frustrate the developers (not to say testers).

Now back to the code reuse. As a programmer, you interact with programs. And you may observe that some programs exhibit the same behavior so that we can generalize. But when you see this common behavior, you, in fact, are operating in the knowledge domain of programs, not in the domain of what your program is actually modeling. In other words, an object of your observation is a program. Not an object of a model which this program is trying to represent. For example, cars usually have a collection of N equal wheels. At the same time, a year consists of N equal days. However, there is nothing in common between class `Year`

and class `Car`

although they can definitely reuse some common code. Neither it would be a good idea to derive one or another from a container.

This brings us to an idea, that code reuse is an entity in the domain of a program analysis. The domain in which we reason about programs and their behavior. It is a worthwhile domain, where we study algorithms and data. In this domain, we have various mechanisms with variable availability in different languages, thus, in general, we have to design this in terms of a language. For example, in Java, we might use a visitor, in places where in OCaml we will use ADT or a first-class function. However, let’s try to think about code reuse without sticking to a particular language or paradigm. When you have several programs that behave mostly the same but differ in some detail, you may substitute these several programs with one program, by abstracting away the differences and creating a general program, that doesn’t depend on those details. Notice, that abstraction and generalization are dual concepts that always come together. In order to generalize something so that it could be applied to more than one thing, you have to create an abstraction that will describe the set of applicable things. For example, if we want to generalize a summation of a list of entities, we have to provide an abstraction of a sum of entities:

```
let rec sum add xs =
| [] -> raise Not_found
| x :: xs -> List.fold_left add x xs
```

We might see that our abstraction is insufficient as it doesn’t handle the empty sum case. So, in fact, we need some sentinel that will denote the empty, sum. Usually, it is called `zero`

, e.g.,

```
let rec sum zero add xs = List.fold_left add zero xs
```

The abstraction that we just devised is called monoid, and there are quite a few algorithms that we can generalize using the monoid abstraction. In fact, `product`

is a sum in monoid where `zero`

is `one`

and `add`

is the multiplication.

In OCaml, we can create abstractions by … abstraction, aka creating a function. Surprisingly, not all languages provide these facilities. This is possible in OCaml due to the parametric polymorphism. Indeed, our `sum`

function is polymorphic, as it could be used in different typing contexts. Or in other words, applied to values of different types, e.g., `int`

s, `float`

s, `strings`

, sets of strings, etc. Not all abstractions actually require polymorphism, as sometimes builtin types of a language provide sufficient abstraction, e.g., you can model plenty of things with `int`

. But in general, abstraction involved a typing. Basically, an abstraction denotes a set of operations applicable to some enitity. For example, monoid is described as

```
module type monoid = sig
type t
val add : t -> t -> t
val zero : t
end
```

alternatively, you can just represent it as a pair of arguments to the function (as we did above), or as a record

```
type 'a monoid = {
add : 'a -> 'a -> 'a;
zero : 'a
}
```

or even as a class or object type.

In classical OOP languages, the only way to specify abstractions were classes, e.g.,

```
struct monoid {
monoid zero() = 0;
monoid add(monoid, monoid) = 0;
};
monoid sum(monoid, list<monoid> elts);
```

Unfortunately, OOP started to confuse abstraction with generalization from the first days of existence, thus they started to implement generic also using classes, e.g.,

```
struct base {
base zero() = 0;
base add(base, base) = 0;
};
struct monoid : base {
monoid sum(list<monoid>);
};
struct Int : monoid {
Int(int init) : value(init) {}
Int zero() {return Int(0); }
Int add(Int x, Int y) { return Int(x.value + y.value);}
private:
int value;
};
```

This all started to bring havoc, as soon as abstractions happen to become more complex. As now we started to have a problem - that subclassing is not subtyping, deal with variances and covariances and other notions that we should have to deal with. Fortunately, in OCaml we can use simple abstractions, or their big brothers functors (which are abstractions on structure level) to deal with it.

To summarize, code reuse should be applied to your code, not to the domain that you’re modeling. I.e., entities of the code reuse are not animals or plants, but programs and data. Albeit both domains are important, they should not be confused. And in the domain of programs, there are quite a few open question about how we can write programs better.