3 ms·
I felt the same way going from Java to Erlang. One hurdle that was difficult for me was understanding Behaviors (which are an abstraction used in both Erlang a
by lliamander 7y ago
I felt the same way going from Java to Erlang.
One hurdle that was difficult for me was understanding Behaviors (which are an abstraction used in both Erlang and Elixir). On the one hand, a Behavior is much like an class/object: it has public methods, internal state, polymorphism (via message passing) and to some extent a notion of inheritance. According to Alan Kay, it's more Object-Oriented than Smalltalk!
However, a Behavior runs in it's own process. Like a typical class, public and private functions are defined in the same file This makes reading the code where a Behavior is defined more difficult because the public methods are executing in the client process, but the callbacks (i.e. private functions) are executing in the Behavior's own process.
One insight I gained from working with Erlang was that the "academic" notion of OOP modeling (i.e. model the entities of your domain as discrete objects) works much better with Erlang's proceses/Behaviors than it ever did with classes/objects in languages like Java.
Objects in languages like Java, C#, Ruby, JS, etc. are much at modeling the architectural components of a system, than at actually modeling domain entities directly. That's actually partly why I really the Pony language: it combines both objects as processes (called Actors) and objects as components/capabilities (called Objects).
- tomn 7y ago> Behavior is much like an class/object: it has public methods, internal state, polymorphism (via message passing) > a Behavior runs in it's own process This doesn't sound right; a behaviour is just a set of functions to be implemented in a 'callback module'; you seem to be talking about processes and modules. I agree with your points though.
- lliamander 7y ago> This doesn't sound right; a behaviour is just a set of functions to be implemented in a 'callback module'; Going back, I see that you are right: the Behavior is technically the common pattern that is shared across specific processes. Is there a name for a process that is defined in a callback module? And really, this complaint about confusing modules spans to more than just callback modules. Most processes define both the client and server functions in the same module. For small modules it's not too big a deal, but even then it is very difficult for someone new to the language to learn how follow the flow of data. Dave Thomas has some interesting ideas about this and other problems, but as I don't do Erlang programming professionally at the moment I haven't had time to really dig in deep.
- toast0 7y ago> Is there a name for a process that is defined in a callback module? I don't think there really is. Where I was working, we would just say this process is a gen_server (or whatever), as if it was a type of process, but this is more of an emergent property of the environment, than a named property. If enumerating the processes, you can guess a process is a gen_server based on erlang:process_info(initial_call, Pid), but that's not definitive because it could have started as something else, then used gen_server:enter_loop to become a gen_server, or started as a gen_server and then become something else. Naming the behavior the same as the module, and including client apis and server and the behavior in the same module is legitimately confusing as well; although, all that being in the same place can be nice, too.
- dnautics 7y agoFYI: behaviour is an API specification for modules, they don't have to run in their own processes. However, it is the case that the most commonly used behaviours are gen_server, gen_statem, supervisor, etc, which do live in their own processes, and it is arguably most useful to use behaviours to determine the callbacks that an abstracted, general process-managing module uses to hook into the module you write that describes the implementation of a GenServer. For an example of a non-process-bound use for a behaviour, one could have "ping" behaviour, which describes running an ICMP ping. You could then describe in abstracted form, the common points between an implementation that uses the linux standard ping, fping, a FFI call to low-level OS hooks and network stacks, a call to the new OTP 22 socket module. Or, in a test environment, write a module where it's backed by a stateful lookup table, where you can assume a ping response, but selectively turn off ping responses to IP addresses to simulate a failed ping response and verify downstream effects.
- ramchip 7y agoA behaviour defines an interface a module can implement, nothing more. A good example of a behaviour that doesn’t involve any process is the SSL session cache: http://erlang.org/doc/man/ssl_session_cache_api.html http://erlang.org/doc/man/ssl_session_cache_api.html If you implement your own cache module (backed by a file, DB, whatever) and it respects this interface, you can then pass it to the SSL functions and they’ll use it instead of the default cache. It just happens that gen_server is both the name of a behaviour, and the name of a module, which can be a bit confusing. The gen_server module implements a generic server process, which is customized by passing it a module that implements the gen_server behaviour (as an argument of `start_link`).