[boilerplate bypath=”fp-oo”]

I feel like I should start with a disclaimer: this post is not advocating building an OO system on top of an FP language. And anyway, the Elixir/Erlang “process” model is arguably a very OO system right out of the box. But this series is about working through the FPOO book, and the exercise that’s up next is to implement a basic OO system on top of an FP language, so that’s what I’m going to do.

First version, without knowledge of class:

```defmodule Objects1 do
import Dict
def new_point(x, y), do: [x: x, y: y]
def x(point), do: get(point, :x)
def y(point), do: get(point, :y)
end
```

(Note: when I wrote this I either didn’t know, or had forgotten, that subscript/square-bracket access was available in Elixir. So you’ll see a lot of get(point, :x) when I probably could have written point[:x].)

```defmodule TestObjects1 do
import FpOoElx.Exercises.Objects1
test "constructing a Point" do
p = new_point(3,5)
assert(x(p) == 3)
assert(y(p) == 5)
end
end
```

Second version, with knowledge of class and shift method:

```defmodule TestObjects2 do
use ExUnit.Case
import FpOoElx.Exercises.Objects2
test "constructing a Point" do
p = new_point(3,5)
assert(x(p) == 3)
assert(y(p) == 5)
assert(class_of(p) == :point)
p = shift(p, 7, -2)
assert(x(p) == 10)
assert(y(p) == 3)
end
doctest FpOoElx.Exercises.Objects2
end
```
```defmodule Objects2 do
import Dict
def new_point(x, y), do: [x: x, y: y, __class_symbol__: :point]
def x(this), do: get(this, :x)
def y(this), do: get(this, :y)
def class_of(object), do: get(object, :__class_symbol__)
def shift(this, xinc, yinc), do: new_point(x(this) + xinc, y(this) + yinc)
<<objects2>>
end
```

I think I’ll switch over to doctests instead of separate unit tests.

```@doc """
## Examples:
iex> p1 = new_point(3, 7)
iex> p2 = new_point(8, -3)
iex> x(p3)
11
iex> y(p3)
4
"""
def add(p1, p2), do: shift(p1, x(p2), y(p2))
```

## Exercise 2: A “new” operator

If I did this exactly like the Clojure version I’d have to call it like this:

```make(&new_point/1, [3, 5])
```

Blerg. I’ll make a macro instead.

```@doc """
## Examples
iex> p = make(point, [3, 5])
iex> class_of(p)
:point
iex> x(p)
3
iex> y(p)
5
"""
defmacro make(class, args) do
{classname,_,_} = class
constructor = binary_to_atom("new_#{classname}")
quote do
unquote(constructor)(unquote_splicing(args))
end
end
```

OK, that was kinda cool. Of course, if I were willing to put up with passing the classname as a symbol rather than as a bareword, I wouldn’t need a macro.

```@doc """
## Examples
iex> p = make2(:point, [3, 5])
iex> class_of(p)
:point
iex> x(p)
3
iex> y(p)
5
"""
def make2(class, args) do
constructor = :"new_#{class}"
code = {constructor, [], args}
{result, _} = Code.eval_quoted(code, binding, delegate_locals_to: __MODULE__)
result
end
```

Note the use of delegate_locals_to: __MODULE__ to enable the eval_quoted to find methods in the current module. I’m still getting the hang of eval-ing in Elixir; there may be a better way to do this.

The next three exercises involve comparing triangles and I just can’t get excited about that, so I’m gonna stop here.