Showing posts with label OOP. Show all posts
Showing posts with label OOP. Show all posts

Friday, June 5, 2015

OOP in Erlang. Part 2. Polymorphism

Encapsulation was covered in previous article of my OOP in Erlang series.

Polymorphism

Polymorphism is ability to present the same interface for different instances (types).

Processes

First of all, process is a unit of encapsulation in Erlang, polymorphism could be implemented on that level.
Client can send the same message to different processes, which will handle the message differently.
For example, we can implement gen_server behaviour in two modules.
serv1.erl
handle_call(message, _From, State) ->
  {reply, 1, State}.
serv2.erl
handle_call(message, _From, State) ->
  {reply, 2, State}.
Then client chooses one of gen_servers and starts it, saving Pid of the process. And then gen_server:call(Pid, message) can be called and caller experiences different behaviour based on module chosen in the beginning.

Dynamic types

Erlang is dynamically typed language, as a result module and even function name could be taken from variable during function call. For example, interfaces of dict and orddict from OTP are unified, and following code shows polymorphism implementation.
Module =
       case Ordering of
           unordered ->
               dict;
           ordered ->
               ordict
       end,
Container = Module:from_list(Values),
Module:find(Key, Container).

Pattern matching

Pattern matching is a powerful feature of the language, which can be used for polymorphism implementation. The idea is that function changes it's behaviour depending on arguments it gets. The most obvious data type to match on is record.
move(#duck{}) -> move_duck();
move(#fish{}) -> move_fish().
Extensive usage of pattern matching for that purpose leads to decoupling of "object" from it's behaviour (business logic), as a result for adding of a new "type" changes in multiple modules are required. This is very similar to Anemic domain model, which has some advantages though.

Conclusion

Polymorphism in Erlang could me implemented in different ways. Even though processes provide the most clear interface for that, developer should not create processes only for modeling business logic, because:
  1. Logic changes quite often and changing all boilerplate code of processes is an overhead.
  2. System becomes more complicated with each new type of process spawned.

Monday, January 26, 2015

OOP in Erlang. Part 1. Encapsulation

Introduction

There is a popular statement, that principles from object oriented programming (OOP) are not be applicable in functional languages and particularly in Erlang. Let's try to analyse it.
The main concepts of object oriented design (OOD) are

  1. Encapsulation.
  2. Polymorphism.
  3. Inheritance

Encapsulation

Encapsulation concept in Erlang could be found at least in process model.

Processes

Each process has it's own state, which can only be modified by handling of message sent to the process. Process is free to ignore any kind of message, handling particular ones.
One of Erlang's "design pattern" is process per message, which encourages to spawn a process for each concurrent instance in a system. In case of HTTP service requests' handling is concurrent, but having encapsulation only on that level is not enough for a good Web framework. Also good people never force client to call gen_server:call/2 for a gen_server they've implemented, they wrap such calls with functions in client API modules.

Modules

Erlang module has export attribute,  which allows to call some functions implemented in it from outside. What else is it, if not splitting to public and private functions in OOP language?
Modules can represent objects even in easier way than processes. For example, queue and proplists. One can say that there is no protection from module's function being called with wrong argument, but the same situation is in Python, where private functions are distinguished from public only by naming conventions.

Conclusion

Erlang has two levels on encapsulation, which could be combined in order to create a good design for system.


To be continued.