Erlang/OTP Forums

Author Message

<  Erlang questions mailing list  ~  Parameterized module idioms

Guest
Posted: Fri Apr 16, 2010 6:11 pm Reply with quote
Guest
Is there a cleaner, more idiomatic way to use object-like parameterized
modules:

-module(echo, [PID]).
-behaviour(gen_server).
-export([start_link/0, echo/1]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
code_change/3]).

start_link() ->
case gen_server:start_link(?MODULE:new(undefined), [], []) of
{ok, Pid} ->
{ok, ?MODULE:new(Pid)};
Else ->
Else
end.

echo(What) ->
gen_server:call(PID, {echo, What}).

handle_call({echo, What}, _From, State) ->
{reply, What, State}.

init([]) -> {ok, []}.
handle_cast(_Msg, _State) -> undefined.
handle_info(_Info, _State) -> undefined.
terminate(_Reason, _State) -> undefined.
code_change(_OldVsn, _State, _Extra) -> undefined.

17> {ok, E} = (echo:new(undefined)):start_link().
{ok,{echo,<0.82.0>}}
18> E:echo("hello, world").
"hello, world"
19>


Post received from mailinglist
gar1t
Posted: Fri Apr 16, 2010 11:59 pm Reply with quote
User Joined: 11 Aug 2009 Posts: 55
On Fri, Apr 16, 2010 at 1:09 PM, Mark Fine <mark.fine@gmail.com> wrote:
> Is there a cleaner, more idiomatic way to use object-like parameterized
> modules:
>
> -module(echo, [PID]).
> -behaviour(gen_server).
> -export([start_link/0, echo/1]).
> -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
> code_change/3]).
>
> start_link() ->
>
View user's profile Send private message
Guest
Posted: Sat Apr 17, 2010 12:08 am Reply with quote
Guest
On Fri, Apr 16, 2010 at 4:56 PM, Garrett Smith <g@rre.tt> wrote:
> On Fri, Apr 16, 2010 at 1:09 PM, Mark Fine <mark.fine@gmail.com> wrote:
>> Is there a cleaner, more idiomatic way to use object-like parameterized
>> modules:
>>
>> -module(echo, [PID]).
>> -behaviour(gen_server).
>> -export([start_link/0, echo/1]).
>> -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
>> code_change/3]).
>>
>> start_link() ->
>>    case gen_server:start_link(?MODULE:new(undefined), [], []) of
>>        {ok, Pid} ->
>>            {ok, ?MODULE:new(Pid)};
>>        Else ->
>>            Else
>>    end.
>>
>> echo(What) ->
>>    gen_server:call(PID, {echo, What}).
>>
>> handle_call({echo, What}, _From, State) ->
>>    {reply, What, State}.
>>
>> init([]) -> {ok, []}.
>> handle_cast(_Msg, _State) -> undefined.
>> handle_info(_Info, _State) -> undefined.
>> terminate(_Reason, _State) -> undefined.
>> code_change(_OldVsn, _State, _Extra) -> undefined.
>>
>> 17> {ok, E} = (echo:new(undefined)):start_link().
>> {ok,{echo,<0.82.0>}}
>> 18> E:echo("hello, world").
>> "hello, world"
>> 19>
>>
>
> I realize there are some fans of parameterized modules. I'm wondering
> though if this:
>
>  E:echo("hello")
>
> provides enough payoff over this:
>
>  echo(E, "hello")
>
> to justify the effort.
>
> I come from an OO background myself, but for whatever reason, the
> second form doesn't bother me. It may be that it's so endemic in
> Erlang that I've gotten used to it.

Technically speaking the difference is:

E:echo("hello") vs. some_module:echo(E, "hello")

The biggest reason I've seen to use parameterized modules is that you
could have a different module that implements the same interface, e.g.
sets and gb_sets and you could change which one you're using without
changing any of the code that consumes it.

I would definitely change the original code to use two modules, one
module to do the start_link stuff, and another module to actually
implement the interface.

-bob

________________________________________________________________
erlang-questions (at) erlang.org mailing list.
See http://www.erlang.org/faq.html
To unsubscribe; mailto:erlang-questions-unsubscribe@erlang.org

Post received from mailinglist
MononcQc
Posted: Sat Apr 17, 2010 12:17 am Reply with quote
User Joined: 14 Aug 2009 Posts: 37 Location: Quebec, Canada
On Fri, Apr 16, 2010 at 8:06 PM, Bob Ippolito <bob@redivi.com> wrote:

>
> Technically speaking the difference is:
>
> E:echo("hello") vs. some_module:echo(E, "hello")
>
> The biggest reason I've seen to use parameterized modules is that you
> could have a different module that implements the same interface, e.g.
> sets and gb_sets and you could change which one you're using without
> changing any of the code that consumes it.
>
> I would definitely change the original code to use two modules, one
> module to do the start_link stuff, and another module to actually
> implement the interface.
>
> -bob
>
> ________________________________________________________________
> erlang-questions (at) erlang.org mailing list.
> See http://www.erlang.org/faq.html
> To unsubscribe; mailto:erlang-questions-unsubscribe@erlang.org
>
> M = sets,
D = M:new().
M:add_element(10, D).

This works as well without a problem. Switch the value of M and if the
interface is the same, nothing changes.


Post received from mailinglist
View user's profile Send private message
Guest
Posted: Sat Apr 17, 2010 1:07 am Reply with quote
Guest
On Fri, Apr 16, 2010 at 5:13 PM, Fred Hebert <mononcqc@gmail.com> wrote:
> On Fri, Apr 16, 2010 at 8:06 PM, Bob Ippolito <bob@redivi.com> wrote:
>>
>> Technically speaking the difference is:
>>
>> E:echo("hello") vs. some_module:echo(E, "hello")
>>
>> The biggest reason I've seen to use parameterized modules is that you
>> could have a different module that implements the same interface, e.g.
>> sets and gb_sets and you could change which one you're using without
>> changing any of the code that consumes it.
>>
>> I would definitely change the original code to use two modules, one
>> module to do the start_link stuff, and another module to actually
>> implement the interface.
>>
> M = sets,
> D = M:new().
> M:add_element(10, D).
>
> This works as well without a problem. Switch the value of M and if the
> interface is the same, nothing changes.

Yes, but now you're passing around two variables instead of one.

-bob

________________________________________________________________
erlang-questions (at) erlang.org mailing list.
See http://www.erlang.org/faq.html
To unsubscribe; mailto:erlang-questions-unsubscribe@erlang.org

Post received from mailinglist
gar1t
Posted: Sat Apr 17, 2010 1:10 am Reply with quote
User Joined: 11 Aug 2009 Posts: 55
On Fri, Apr 16, 2010 at 7:06 PM, Bob Ippolito <bob@redivi.com> wrote:
> On Fri, Apr 16, 2010 at 4:56 PM, Garrett Smith <g@rre.tt> wrote:
>> On Fri, Apr 16, 2010 at 1:09 PM, Mark Fine <mark.fine@gmail.com> wrote:
>>> Is there a cleaner, more idiomatic way to use object-like parameterized
>>> modules:
>>>
>>> -module(echo, [PID]).
>>> -behaviour(gen_server).
>>> -export([start_link/0, echo/1]).
>>> -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
>>> code_change/3]).
>>>
>>> start_link() ->
>>>
View user's profile Send private message
Guest
Posted: Sat Apr 17, 2010 1:13 am Reply with quote
Guest
On Fri, Apr 16, 2010 at 6:06 PM, Garrett Smith <g@rre.tt> wrote:
> On Fri, Apr 16, 2010 at 7:06 PM, Bob Ippolito <bob@redivi.com> wrote:
>> On Fri, Apr 16, 2010 at 4:56 PM, Garrett Smith <g@rre.tt> wrote:
>>> On Fri, Apr 16, 2010 at 1:09 PM, Mark Fine <mark.fine@gmail.com> wrote:
>>>> Is there a cleaner, more idiomatic way to use object-like parameterized
>>>> modules:
>>>>
>>>> -module(echo, [PID]).
>>>> -behaviour(gen_server).
>>>> -export([start_link/0, echo/1]).
>>>> -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
>>>> code_change/3]).
>>>>
>>>> start_link() ->
>>>>    case gen_server:start_link(?MODULE:new(undefined), [], []) of
>>>>        {ok, Pid} ->
>>>>            {ok, ?MODULE:new(Pid)};
>>>>        Else ->
>>>>            Else
>>>>    end.
>>>>
>>>> echo(What) ->
>>>>    gen_server:call(PID, {echo, What}).
>>>>
>>>> handle_call({echo, What}, _From, State) ->
>>>>    {reply, What, State}.
>>>>
>>>> init([]) -> {ok, []}.
>>>> handle_cast(_Msg, _State) -> undefined.
>>>> handle_info(_Info, _State) -> undefined.
>>>> terminate(_Reason, _State) -> undefined.
>>>> code_change(_OldVsn, _State, _Extra) -> undefined.
>>>>
>>>> 17> {ok, E} = (echo:new(undefined)):start_link().
>>>> {ok,{echo,<0.82.0>}}
>>>> 18> E:echo("hello, world").
>>>> "hello, world"
>>>> 19>
>>>>
>>>
>>> I realize there are some fans of parameterized modules. I'm wondering
>>> though if this:
>>>
>>>  E:echo("hello")
>>>
>>> provides enough payoff over this:
>>>
>>>  echo(E, "hello")
>>>
>>> to justify the effort.
>>>
>>> I come from an OO background myself, but for whatever reason, the
>>> second form doesn't bother me. It may be that it's so endemic in
>>> Erlang that I've gotten used to it.
>>
>> Technically speaking the difference is:
>>
>> E:echo("hello") vs. some_module:echo(E, "hello")
>
> Yup, sorry, I did deceptively simplify my example Smile
>
>> The biggest reason I've seen to use parameterized modules is that you
>> could have a different module that implements the same interface, e.g.
>> sets and gb_sets and you could change which one you're using without
>> changing any of the code that consumes it.
>
> I've found that custom behaviors also work well for this, at least for
> interfaces to processes.

Yeah well, processes can do everything that parameterized modules can
do, except perform well if you're trying to do a lot of concurrency Wink

-bob

________________________________________________________________
erlang-questions (at) erlang.org mailing list.
See http://www.erlang.org/faq.html
To unsubscribe; mailto:erlang-questions-unsubscribe@erlang.org

Post received from mailinglist
gar1t
Posted: Sat Apr 17, 2010 1:36 am Reply with quote
User Joined: 11 Aug 2009 Posts: 55
On Fri, Apr 16, 2010 at 8:04 PM, Bob Ippolito <bob@redivi.com> wrote:
> On Fri, Apr 16, 2010 at 5:13 PM, Fred Hebert <mononcqc@gmail.com> wrote:
>> On Fri, Apr 16, 2010 at 8:06 PM, Bob Ippolito <bob@redivi.com> wrote:
>>>
>>> Technically speaking the difference is:
>>>
>>> E:echo("hello") vs. some_module:echo(E, "hello")
>>>
>>> The biggest reason I've seen to use parameterized modules is that you
>>> could have a different module that implements the same interface, e.g.
>>> sets and gb_sets and you could change which one you're using without
>>> changing any of the code that consumes it.
>>>
>>> I would definitely change the original code to use two modules, one
>>> module to do the start_link stuff, and another module to actually
>>> implement the interface.
>>>
>> M = sets,
>> D = M:new().
>> M:add_element(10, D).
>>
>> This works as well without a problem. Switch the value of M and if the
>> interface is the same, nothing changes.
>
> Yes, but now you're passing around two variables instead of one.

I'd be tempted to create a wrapper that took the impl module in its
new function and maintained it as internal state.

-module(gen_dict).

-define(state, {impl, impl_state}).

new(Impl) ->
#state{impl=Impl, impl_state=Impl:new()}.

store(Key, Val, #state{impl=Impl, impl_state=ImplState}=S) ->
S#state{impl_state=Impl:store(Key, Val, ImplState)}.

... and so on...

And to use (obviously):

D = gen_dict:new(dict),
D2 = gen_dict:store(foo, bar, D)

Granted, there's a fair amount of horsing around, but not terrible.
And your generic API is explicit.

Behaviors should work for this as well as they just enforce an exported API.

Garrett

________________________________________________________________
erlang-questions (at) erlang.org mailing list.
See http://www.erlang.org/faq.html
To unsubscribe; mailto:erlang-questions-unsubscribe@erlang.org

Post received from mailinglist
View user's profile Send private message
MononcQc
Posted: Sat Apr 17, 2010 1:57 am Reply with quote
User Joined: 14 Aug 2009 Posts: 37 Location: Quebec, Canada
The biggest 'advantage' of parametrized modules that I see is that you shift
the burden of carrying state from a variable to a module name.

In this module:
-module(y, [Name,Age]).
-compile(export_all).

action1() -> io:format("Hello, ~p!~n",[Name]).

get_age() -> Age.

However, my biggest problem with them show up were I to add the following
function:
ret_fn() -> fun(Age) -> Age + 5 end.

and then tried to compile it, all of a sudden I get the error "./y.erl:8:
Warning: variable 'Age' shadowed in 'fun'". Of course, this is not
problematic if you can hold all the info about the module parameters and
their names in your head, but if you were to look only at the function where
the error takes place, you would get no sign whatsoever of where the error
comes from.
Now if I were to use the variable 'Name' for any other purpose; I'd get a
run time error telling "** error: no match of right hand side value < ...
>." Again, there I'm having no obvious sign of where the error might come
from -- I have to look for the module definition to know the cause of it.

The way I see it is that parametrized modules reduce the amount of typing
you need to do at the expense of logical simplicity. I'm not sure I'm too
enthusiastic at the idea of making programs harder to reason about for the
sake of typing less.

I guess the problem is going to be less and less apparent with programmers
getting used to it, but yeah. That's my point of view.


Post received from mailinglist
View user's profile Send private message
Guest
Posted: Sat Apr 17, 2010 9:41 am Reply with quote
Guest
> The biggest 'advantage' of parametrized modules that I see is that you shift
> the burden of carrying state from a variable to a module name.

IMO this is also a disadvantage, but not specific to parametrized
modules: using variables for module references makes static analysis
harder (both in your head and in code).

For example, [unless you're doing some crazy rewriting tricks] it's
obvious which function this is calling:

some_module:echo(E, "hello")

This isn't so obvious:

E:echo("hello")

Here you have to trace back to the definition of E to find out what
module it refers to.

Tim

________________________________________________________________
erlang-questions (at) erlang.org mailing list.
See http://www.erlang.org/faq.html
To unsubscribe; mailto:erlang-questions-unsubscribe@erlang.org

Post received from mailinglist
Guest
Posted: Sat Apr 17, 2010 10:59 am Reply with quote
Guest
> For example, [unless you're doing some crazy rewriting tricks] it's
> obvious which function this is calling:
>
>
Guest
Posted: Sat Apr 17, 2010 4:38 pm Reply with quote
Guest
On Sat, Apr 17, 2010 at 3:57 AM, Hynek Vychodil <hynek@gooddata.com> wrote:
>> For example, [unless you're doing some crazy rewriting tricks] it's
>> obvious which function this is calling:
>>
>>    some_module:echo(E, "hello")
>>
>> This isn't so obvious:
>>
>>    E:echo("hello")
>>
>> Here you have to trace back to the definition of E to find out what
>> module it refers to.
>
> I agree with you. It is issue especially in projects with lack of
> documentation as mochiweb for example. I thought parametrized modules
> is great idea until I met mochiweb.

To be fair there's edocs for all of the public functions and there's
really only one parameterized module you have to use
(mochiweb_request). It's really not that hard to figure it out, you
only look in one place for the docs. Yes, it should have some
expository documentation but that's not something I ever got around to
doing, and it's why I never did the other stuff like make a webpage
for it or release tarballs.

-bob

________________________________________________________________
erlang-questions (at) erlang.org mailing list.
See http://www.erlang.org/faq.html
To unsubscribe; mailto:erlang-questions-unsubscribe@erlang.org

Post received from mailinglist
kagato
Posted: Sat Apr 17, 2010 9:32 pm Reply with quote
User Joined: 30 Dec 2007 Posts: 85
> For example, [unless you're doing some crazy rewriting tricks] it's
> obvious which function this is calling:
>
> some_module:echo(E, "hello")
>
> This isn't so obvious:
>
> E:echo("hello")
>
> Here you have to trace back to the definition of E to find out what
> module it refers to.
Actually, that's the point. There are two good reasons to do this.

1. Hide massive amounts of information.

While this runs counter to your point, sometimes there's so much state data that it makes code impossible to maintain if you explicitly write it all. This neatly hides it. More to the point, Erlang already does this with records. They allow you to pick and assign bits of the state without seeing it all. You still have to trace the definition back to the record. I don't really see this as different.

2. Polymorphism

This is the big win. E might refer to any number of classes which are instantiated in any number of actual combinations. But another way, imagine that you separated this out into different types. Then the call would be:

> T:echo(E,"hello")


This isn't nearly as nice as:

> E:echo("hello")


In this case, E holds all of the state, including the module. This is no different than gen_server and friends. It just considers the callback module to be part of the state, bundles them together out of side, and gives a reasonably short syntax to show them. In practice, I don't think this is that hard to debug--especially in the cases where it yields shorter, simpler code.

--
Jayson Vantuyl
kagato@souja.net


________________________________________________________________
erlang-questions (at) erlang.org mailing list.
See http://www.erlang.org/faq.html
To unsubscribe; mailto:erlang-questions-unsubscribe@erlang.org

Post received from mailinglist
View user's profile Send private message
Guest
Posted: Sat Apr 17, 2010 11:50 pm Reply with quote
Guest
>
> To be fair there's edocs for all of the public functions and there's
> really only one parameterized module you have to use
> (mochiweb_request). It's really not that hard to figure it out, you
> only look in one place for the docs. Yes, it should have some
> expository documentation but that's not something I ever got around to
> doing, and it's why I never did the other stuff like make a webpage
> for it or release tarballs.
>
> -bob
>

To be fair there is edocs for all the public functions but in those
days It was mostly just only name of function, one sentence for some
one and may be there was some one with more but I was not lucky enough
to find them. Even information that Req (parameter of almost each
function) is implemented in mochiweb_request module was not pointed
from most of documentation if ever. Jayson Vantuyl is pointing in
another mail that same polymorphism can be done without parametrized
module and all this is just bad experience with one application. Yes,
it seems true. Well, parametrized modules doesn't bring more issues
than present in rest of Erlang.

--
--Hynek (Pichi) Vychodil

________________________________________________________________
erlang-questions (at) erlang.org mailing list.
See http://www.erlang.org/faq.html
To unsubscribe; mailto:erlang-questions-unsubscribe@erlang.org

Post received from mailinglist
Guest
Posted: Sun Apr 18, 2010 9:15 am Reply with quote
Guest
By the way,
are there any news on whether and if so how will parametrized modules be
supported in R14?

Regards,
Zoltan.

________________________________________________________________
erlang-questions (at) erlang.org mailing list.
See http://www.erlang.org/faq.html
To unsubscribe; mailto:erlang-questions-unsubscribe@erlang.org

Post received from mailinglist

Display posts from previous:  

All times are GMT
Page 1 of 3
Goto page 1, 2, 3  Next
This forum is locked: you cannot post, reply to, or edit topics.

Jump to:  

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum