Erlang Mailing Lists

Author Message

<  Erlang questions mailing list  ~  Parameterized module idioms

t
Posted: Sun Apr 18, 2010 11:19 am Reply with quote
User Joined: 30 Sep 2008 Posts: 133
On Sun, Apr 18, 2010 at 10:12 AM, Zoltan Lajos Kis <kiszl@tmit.bme.hu> wrote:
> By the way,
> are there any news on whether and if so how will parametrized modules be
> supported in R14?

Kenneth said the following at Erlang Factory SFBay 2010:
"Tentative: Parameterized modules officially supported and
with more efficient implementation."

________________________________________________________________
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
kagato
Posted: Sun Apr 18, 2010 7:42 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: Mon Apr 19, 2010 3:22 am Reply with quote
Guest
On Apr 18, 2010, at 9:28 AM, Jayson Vantuyl 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.
> Actually, that's the point. There are two good reasons to do this.
>
> 1. Hide massive amounts of information.

We can already do this with plain old closures.
Instead of
E:echo("hello")
we can do
E(echo, "hello")

To a first approximation, any module with parameters can be written
as a function that returns a closure (the standard OO-in-FP trick).
>
> 2. Polymorphism

Also trivially doable with plain old closures.



________________________________________________________________
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: Mon Apr 19, 2010 3:45 am Reply with quote
Guest
On Sunday, April 18, 2010, Richard O'Keefe <ok@cs.otago.ac.nz> wrote:
>
> On Apr 18, 2010, at 9:28 AM, Jayson Vantuyl 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.
>
> Actually, that's the point.  There are two good reasons to do this.
>
> 1.  Hide massive amounts of information.
>
>
> We can already do this with plain old closures.
> Instead of
>        E:echo("hello")
> we can do
>        E(echo, "hello")
>
> To a first approximation, any module with parameters can be written
> as a function that returns a closure (the standard OO-in-FP trick).
>
>
> 2.  Polymorphism
>
>
> Also trivially doable with plain old closures.

Trivial, but requires a lot of boilerplate code and certainly isn't
any easier to understand or debug than parameterized modules. It also
becomes impossible to write a useful type spec if you use closures
like that.

-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
Guest
Posted: Mon Apr 19, 2010 10:27 pm Reply with quote
Guest
I pointed out that modules with parameters give us nothing
that plain old closures don't, in response to which
On Apr 19, 2010, at 3:43 PM, Bob Ippolito wrote:

>>
>
> Trivial, but requires a lot of boilerplate code and certainly isn't
> any easier to understand or debug than parameterized modules. It also
> becomes impossible to write a useful type spec if you use closures
> like that.

(a) Such boilerplate code as is required can be automatically generated.
(b) The possibility or otherwise of useful type specs depends on what
the type language allows. Dependent type systems would have no
trouble at all; the question of _how much_ of the machinery of a
dependent type system one needs is an empirical matter.
(c) A dismissal of closures on such grounds is ALSO a dismissal of
modules with parameters since each can simulate the other.


________________________________________________________________
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: Mon Apr 19, 2010 10:48 pm Reply with quote
Guest
On Mon, Apr 19, 2010 at 3:25 PM, Richard O'Keefe <ok@cs.otago.ac.nz> wrote:
> I pointed out that modules with parameters give us nothing
> that plain old closures don't, in response to which
> On Apr 19, 2010, at 3:43 PM, Bob Ippolito wrote:
>
>>>
>>
>> Trivial, but requires a lot of boilerplate code and certainly isn't
>> any easier to understand or debug than parameterized modules. It also
>> becomes impossible to write a useful type spec if you use closures
>> like that.
>
> (a) Such boilerplate code as is required can be automatically generated.
> (b) The possibility or otherwise of useful type specs depends on what
>    the type language allows.  Dependent type systems would have no
>    trouble at all; the question of _how much_ of the machinery of a
>    dependent type system one needs is an empirical matter.
> (c) A dismissal of closures on such grounds is ALSO a dismissal of
>    modules with parameters since each can simulate the other.

I was speaking practically, not theoretically. The current
implementation of Erlang, edoc, and related tools have much better
support for parameterized modules than for using closures to emulate
parameterized modules.

We actually use the closure approach more often, because closures also
have desirable properties with regard to module reloading. Our use of
parameterized modules is almost entirely limited to mochiweb_request.
However, when we do use closures to capture state and provide a
module's worth of features it is not elegant due to boilerplate code
and Erlang syntax "features".

-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
Guest
Posted: Tue Apr 20, 2010 12:27 pm Reply with quote
Guest
Hi all,

I have not used much parameterized modules, but was very delighted when
did do, and I think they gives us something, in practice.

Richard O'Keefe wrote:
> I pointed out that modules with parameters give us nothing
> that plain old closures don't, in response to which

Closures must be passed somehow, if they are to be used in a function.
If I am writing many functions which use some nonrelated parameters,
some closures are being passed around. That is already too much
pollution for my tastes.

>> Trivial, but requires a lot of boilerplate code and certainly isn't
>> any easier to understand or debug than parameterized modules. It also
>> becomes impossible to write a useful type spec if you use closures
>> like that.
>
> (a) Such boilerplate code as is required can be automatically generated.

If some code would need to be generated if I didn't have parameterized
modules, then parameterized modules already give me something.

Let's look at some examples (from a homemade "database" I wrote some
time ago).

The more simple use may be for substituting constants with something
calculated at runtime; e.g.

Instead of

need_dump(Tab, LogOps) -> LogOps > ?DUMPLIMIT * ets:info(Tab, size).

I can have

need_dump(Tab, LogOps) -> LogOps > DumpLimit * ets:info(Tab, size).

with no change in the interface of the function.

But it becomes much more interesting when modules themselves are used as
parameters of other modules.

The first version had a constant directory path defined and used by a
module pets_lib that served as a sort of general library. Then other
modules used pets_lib.

For example, a module pets_tm would have somewhere:

Res = pets_lib:delete_table(Tab),

How do I make the path (as well as many other configuration parameters)
a value chosen at runtime, with little effort in rewriting the code
which didn´t contemplate such possibility beforehand? Making pets_lib a
parameterized module. What is the impact of that on client code? A
simple change to:

Res = Lib:delete_table(Tab),

It looks pretty much the same, but now we have this Lib variable. If we
were using closures, the closure would have to be passed somehow (who
knows how many levels of invocations) until is was available to the
function which performs this invocation. But if the pets_lib
instantiation is a parameter of pets_tm, then I can use statements like
the above all over pets_tm by doing a simple:

:%s/pets_lib/Lib/g

and making pets_tm parameterized; e.g.

-module(pets_tm, [Lib, DumpLimit]).

Nothing much changes, code is basically reused, we are programming
mostly with plain old functions. The parameters that represent modules
can even have pleasant names, as we do not need to worry about module
namespace pollution in client code and we can rename modules easily
without that having much impact on client code.

Then we only need to glue modules together at service starting time; e.g.

start_link() ->
start_link(#pets_config{dir="PETS", gc={100,0.1,0.3},
sync_delay=1000}).

init(#pets_config{dir=Dir, gc={MT, CR, PR}, sync_delay=SyncDelay}) ->
process_flag(trap_exit, true),
pets_locker:start_link(),
Lib = pets_lib:new(Dir),
Tabs = Lib:init(),
(pets_gc:new(Lib, MT, CR, PR)):start_link(),
Inserters = 2 * erlang:system_info(schedulers),
LastTid = (pets_loader:new(Lib, ?FILE_READERS,
Inserters)):load_tables(Tabs),
(pets_writer:new(Lib, SyncDelay)):start_link(),
(pets_tm:new(Lib, ?DUMP_LIMIT)):start_link(LastTid),
{ok, nostate}.

(Ironically DumpLimit is still a define here in the "main". Wink)

I think all this is nice and very practical. If languages like ML have
first class modules and that is ok, what is the problem in Erlang
adopting this nice looking concept?

Btw there is something which irritates me in the above: Having to write
parenthesis as in:

(pets_gc:new(Lib, MT, CR, PR)):start_link(),

it should be possible to just write:

pets_gc:new(Lib, MT, CR, PR):start_link(),

(and I profoundly hate the "new" keyword, but that is another story)

Best Regards,
Paulo















________________________________________________________________
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
vladdu
Posted: Tue Apr 20, 2010 2:06 pm Reply with quote
User Joined: 28 Feb 2005 Posts: 397 Location: Gothenburg, Sweden
Hi,

There have been many interesting arguments for and against
parametrized modules and I will add a couple of my own, that reflect
my feelings about them. I am lazy and will not quote the original
text, I hope that won't create misunderstandings.

* Of course it's easier to use module parameters instead of passing
closures or state around. Just like it's easier to use global
variables instead of function arguments. That is, as long as you can
remember them all and until something breaks because of a change in a
seemingly unrelated module... There's a reason some people like the
functional style better.

* Personally, I don't think it's a good idea to try to graft features
on a language, for which it wasn't designed from the start. Most of
the time the result is an ugly hybrid. It feels a lot better to
implement different languages targeting the platform, each matching a
different style.

* Parametrized modules aren't the same thing as modules as a data
type. At the moment, they are basically syntax sugar and there are
some weird effects (bugs!) because of that:
> {lists,hello,world}:reverse([1,2,3]).
[3,2,1|{lists,hello,world}]
The (higher-level) reason for this bug is just that there is no module
data type to query if it is parametrized or not.

best regards,
Vlad

________________________________________________________________
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: Tue Apr 20, 2010 3:20 pm Reply with quote
Guest
This boggles me:

If you create a new "instance" of a module with a parameter, then you
need to have that "instance variable" around to call it right? So you
need to keep it somewhere... as a state.

So in any case you need to keep a state, in other words you haven't
achieved anything (except perhaps making your code more obfuscated).

So _why_ is it ["of course"] "easier to use module parameters instead of
passing closures or state around"?

I must be missing some important detail somewhere...

/Mazen

On 20/04/2010 16:04, Vlad Dumitrescu wrote:
> Hi,
>
> There have been many interesting arguments for and against
> parametrized modules and I will add a couple of my own, that reflect
> my feelings about them. I am lazy and will not quote the original
> text, I hope that won't create misunderstandings.
>
> * Of course it's easier to use module parameters instead of passing
> closures or state around. Just like it's easier to use global
> variables instead of function arguments. That is, as long as you can
> remember them all and until something breaks because of a change in a
> seemingly unrelated module... There's a reason some people like the
> functional style better.
>
> * Personally, I don't think it's a good idea to try to graft features
> on a language, for which it wasn't designed from the start. Most of
> the time the result is an ugly hybrid. It feels a lot better to
> implement different languages targeting the platform, each matching a
> different style.
>
> * Parametrized modules aren't the same thing as modules as a data
> type. At the moment, they are basically syntax sugar and there are
> some weird effects (bugs!) because of that:
> > {lists,hello,world}:reverse([1,2,3]).
> [3,2,1|{lists,hello,world}]
> The (higher-level) reason for this bug is just that there is no module
> data type to query if it is parametrized or not.
>
> best regards,
> Vlad
>
> ________________________________________________________________
> erlang-questions (at) erlang.org mailing list.
> See http://www.erlang.org/faq.html
> To unsubscribe; mailto:erlang-questions-unsubscribe@erlang.org
>
>

---------------------------------------------------

---------------------------------------------------

WE'VE CHANGED NAMES!

Since January 1st 2010 Erlang Training and Consulting Ltd. has become ERLANG SOLUTIONS LTD.

www.erlang-solutions.com


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

---------------------------------------------------

---------------------------------------------------

WE'VE CHANGED NAMES!

Since January 1st 2010 Erlang Training and Consulting Ltd. has become ERLANG SOLUTIONS LTD.

www.erlang-solutions.com

Post received from mailinglist
Guest
Posted: Tue Apr 20, 2010 3:23 pm Reply with quote
Guest
On Tuesday, April 20, 2010, Vlad Dumitrescu wrote:

> * Personally, I don't think it's a good idea to try to graft features
> on a language, for which it wasn't designed from the start. Most of
> the time the result is an ugly hybrid. It feels a lot better to
> implement different languages targeting the platform, each matching a
> different style.

I agree, preferring a small, succinct language to a larger language
providing many ways to do things (e.g., Scheme vs. Common Lisp). A smaller
language results in a smaller set of more common idioms that are easily
recognized and understood by programmers. It also reduces the barrier to
entry for new programmers, who can easily grasp the whole language and
easily read other people's code sooner.

I would advocate, therefore, keeping parameterized modules on the fringes,
without official blessing. By withholding official blessing, it makes
programmers consider alternative -- more common and idiomatic -- ways of
doing things.

Steve Davis described a couple of months ago why he has tended to convert
parameterized modules to unparameterized modules over time:
<http://www.erlang.org/cgi-bin/ezmlm-cgi?4:mss:49602:aicfhmngkhodmclhlnak>.
That was actually an interesting thread on this subject, and I gained some
good insight into the use of parameterized modules.

Cheers,

DBM


________________________________________________________________
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: Tue Apr 20, 2010 4:48 pm Reply with quote
Guest
Hi,

Vlad Dumitrescu wrote:

> * Of course it's easier to use module parameters instead of passing
> closures or state around. Just like it's easier to use global
> variables instead of function arguments. That is, as long as you can
> remember them all and until something breaks because of a change in a
> seemingly unrelated module... There's a reason some people like the
> functional style better.

Some of the nice things in functional style are absence of side effects
and referential transparency. Updating global vars may be a problem, but
we are not talking about that. Using parameterized modules will not make
us have global (mutable) variables or side effects (more than we already
have in the language, which is not purely functional), neither will we
loose referential transparency. This has nothing to do with loosing
functional style.

I am not talking about emulating objects and programming with a
different style; I see an important use of parameterized modules to
avoid having to thread all over things that for all practical purposes
are "constants".

People say the difference between:

E:f(...)

and

m:f(..., E)

is not much and so whats the fuss. Its not this difference that may be
significant, but to have to propagate, split, and reconstruct the
components that make up E until they reach this point in the program,
meanwhile polluting and obfuscating "innocent" functions in the
invocation chain.

> * Personally, I don't think it's a good idea to try to graft features
> on a language, for which it wasn't designed from the start. Most of
> the time the result is an ugly hybrid. It feels a lot better to
> implement different languages targeting the platform, each matching a
> different style.

From this reasoning we would not have funs as they did not exist from
the start. But anyway, parameterized modules are pretty orthogonal to
the main features of the language.

> * Parametrized modules aren't the same thing as modules as a data
> type. At the moment, they are basically syntax sugar and there are

Why not? I can already pass them around and store them in data
structures, like I do for closures; what remains to be added is proper
support so that modules are a new runtime type and I can do type
testing, e.g. is_module/1 and so on.

> some weird effects (bugs!) because of that:
> > {lists,hello,world}:reverse([1,2,3]).
> [3,2,1|{lists,hello,world}]
> The (higher-level) reason for this bug is just that there is no module
> data type to query if it is parametrized or not.

This is not a problem with the concept itself but with the (lack) of a
proper implementation. Some strange things could also happen before
proper support for funs was added.

I don´t know what the plans are, but yes, it would be nice to have them
properly supported and not as the hack they are now.

Regards,
Paulo

________________________________________________________________
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: Tue Apr 20, 2010 6:42 pm Reply with quote
Guest
Mazen Harake writes:
> This boggles me:
>
> If you create a new "instance" of a module with a parameter, then you
> need to have that "instance variable" around to call it right? So you
> need to keep it somewhere... as a state.
>
> So in any case you need to keep a state, in other words you haven't
> achieved anything (except perhaps making your code more obfuscated).
>
> So _why_ is it ["of course"] "easier to use module parameters instead of
> passing closures or state around"?
>
> I must be missing some important detail somewhere...

Consider the parts of the code that uses the module parameters.

________________________________________________________________
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
vladdu
Posted: Tue Apr 20, 2010 7:07 pm Reply with quote
User Joined: 28 Feb 2005 Posts: 397 Location: Gothenburg, Sweden
On Tue, Apr 20, 2010 at 17:15, Mazen Harake
<mazen.harake@erlang-solutions.com> wrote:
> If you create a new "instance" of a module with a parameter, then you need
> to have that "instance variable" around to call it right? So you need to
> keep it somewhere... as a state.
>
> So in any case you need to keep a state, in other words you haven't achieved
> anything (except perhaps making your code more obfuscated).
>
> So _why_ is it ["of course"] "easier to use module parameters instead of
> passing closures or state around"?

Hi,

If you send state around the functional way, it has to be a parameter
to all the functions that use some part of that state. If the state
data changes, it may be needed to update all these places (if the
state representation wasn't flexible enough).

If the state is globally accessible, you just use the appropriate
variable where it is needed.

regards,
Vlad

________________________________________________________________
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: Wed Apr 21, 2010 2:03 am Reply with quote
Guest
On Apr 20, 2010, at 11:25 PM, Paulo S
Guest
Posted: Wed Apr 21, 2010 2:46 am Reply with quote
Guest
On Apr 21, 2010, at 7:04 AM, Vlad Dumitrescu wrote:

> On Tue, Apr 20, 2010 at 17:15, Mazen Harake
> <mazen.harake@erlang-solutions.com> wrote:
>> If you create a new "instance" of a module with a parameter, then
>> you need
>> to have that "instance variable" around to call it right? So you
>> need to
>> keep it somewhere... as a state.
>>
>> So in any case you need to keep a state, in other words you haven't
>> achieved
>> anything (except perhaps making your code more obfuscated).
>>
>> So _why_ is it ["of course"] "easier to use module parameters
>> instead of
>> passing closures or state around"?
>
> Hi,
>
> If you send state around the functional way, it has to be a parameter
> to all the functions that use some part of that state. If the state
> data changes, it may be needed to update all these places (if the
> state representation wasn't flexible enough).
>
> If the state is globally accessible, you just use the appropriate
> variable where it is needed.

The "it has to be a parameter ..." part is true of Erlang right
now, not a truth about "the functional way" in general.

"if the state representation wasn't flexible enough" applies with
equal, if not greater, force to module parameters: if we used to
have a parameter Foo and now find that it needs to be split into
Foo proper and Fooly, we still should _review_ each occurrence of
Foo to see what to do about it.

Actually, what we're discussing here is not STATE (which changes)
but CONTEXT (which doesn't). Module parameters do not support state.
Other functional languages usually handle this with nested functions,
not with module parameters.



________________________________________________________________
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 2 of 3
Goto page Previous  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