Last active
April 26, 2016 16:10
-
-
Save sayotte/7741976 to your computer and use it in GitHub Desktop.
Erlang inheritance in the gen_server model.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(child). | |
-behaviour(gen_server). | |
-export([start_link/1, init/1]). | |
-export([get_child_att/1, handle_get_child_att/3]). | |
-export([set_child_att/2, handle_set_child_att/3]). | |
-extends(parent). | |
-include("parent_type.hrl"). | |
-include("child_type.hrl"). | |
start_link(_Args) -> | |
gen_server:start_link(?MODULE, [], []). | |
init(_Args) -> | |
State = #parent_type{startup_mfa = {?MODULE, start_link, []}, | |
child_state = #child_type{} }, | |
{ok, State}. | |
get_child_att(Pid) -> | |
gen_server:call(Pid, {handle_get_child_att, none}). | |
handle_get_child_att(_Args, _From, State) -> | |
ChildState = State#parent_type.child_state, | |
{reply, ChildState#child_type.child_att, State}. | |
set_child_att(Pid, Value) -> | |
gen_server:call(Pid, {handle_set_child_att, Value}). | |
handle_set_child_att(Value, _From, State) -> | |
OldChildState = State#parent_type.child_state, | |
NewChildState = OldChildState#child_type{child_att = Value}, | |
NewState = State#parent_type{child_state = NewChildState}, | |
{reply, {ok, set_child_att}, NewState}. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-record(child_type, {child_att}). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Eshell V5.9.1 (abort with ^G) | |
1> rr(parent). | |
[parent_type] | |
2> rr(child). | |
[child_type,parent_type] | |
3> | |
3> | |
3> {ok, P1} = child:start_link(none). | |
{ok,<0.42.0>} | |
4> | |
4> | |
4> parent:get_state(P1). | |
#parent_type{startup_mfa = {child,start_link,[]}, | |
parent_att = undefined, | |
child_state = #child_type{child_att = undefined}} | |
5> child:get_state(P1). | |
#parent_type{startup_mfa = {child,start_link,[]}, | |
parent_att = undefined, | |
child_state = #child_type{child_att = undefined}} | |
6> | |
6> | |
6> child:get_parent_att(P1). | |
undefined | |
7> child:set_parent_att(P1, a_value). | |
{ok,set_parent_att} | |
8> child:get_parent_att(P1). | |
a_value | |
9> | |
9> | |
9> child:get_child_att(P1). | |
undefined | |
10> child:set_child_att(P1, another_value). | |
{ok,set_child_att} | |
11> child:get_child_att(P1). | |
another_value |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The Erlang compiler gives us the "-extends()" attribute which allows us to inherit any functions not redefined in our own module. This doesn't jive very well with the gen_server behaviour though, for which the primary entry points into the module's features are handle_call/3, handle_cast/2, and handle_info/2. Any definition of these in the parent module will be overwritten rather than "extended" when we use the "-extends()" compiler pragma. | |
It's possible to work around this by implementing handle_call/3 and family as controllers, which decide based on their arguments which other function in the module to call. | |
This is an incomplete, but working, example of a parent/child module pair. | |
I can think of a few reasons why this is a bad idea:<br> | |
1- it makes your OTP code look like something else, ergo hard to read for others<br> | |
2- you're forced to export both the external API *and* the internal top-level handler routines for every feature<br> | |
3- it's obviously a hack<br> | |
... But I don't know of a better way right now :) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(parent). | |
-export([handle_call/3]). | |
-export([get_state/1, handle_get_state/3]). | |
-export([get_parent_att/1, handle_get_parent_att/3]). | |
-export([set_parent_att/2, handle_set_parent_att/3]). | |
-include("parent_type.hrl"). | |
handle_call({Op, Args}, From, State) -> | |
SubModule = element(1, State#parent_type.startup_mfa), | |
apply(SubModule, Op, [Args, From, State]). | |
get_state(Pid) -> | |
gen_server:call(Pid, {handle_get_state, none}). | |
handle_get_state(_Args, _From, State) -> | |
{reply, State, State}. | |
get_parent_att(Pid) -> | |
gen_server:call(Pid, {handle_get_parent_att, none}). | |
handle_get_parent_att(_Args, _From, State) -> | |
{reply, State#parent_type.parent_att, State}. | |
set_parent_att(Pid, Value) -> | |
gen_server:call(Pid, {handle_set_parent_att, Value}). | |
handle_set_parent_att(Value, _From, State) -> | |
NewState = State#parent_type{parent_att = Value}, | |
{reply, {ok, set_parent_att}, NewState}. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-record(parent_type, | |
{ | |
startup_mfa, | |
parent_att, | |
child_state | |
}). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment