| Author |
Message |
< Erlang ~ How to have a dynamic reference to a module? |
| jacek99 |
Posted: Thu Jun 04, 2009 1:54 pm |
|
|
|
User
Joined: 26 May 2009
Posts: 27
Location: Montreal, Canada
|
Let's say I have two implementations of some logic in 2 separate modules:
module1
module2
Depending on a config file I would like to use one of the two.
In a lang like Java, they would be objects that implement the same interface, I would instantiate it to the reference of the interface type and just pass it around.
But I am not sure at all how to do the equivalent in Erlang/OTP.
I presume both modules should implement the same behavior?
But how do I take it from there...what sort of language construct would you need to assign an instance of a behavior to a module that implements it and pass that around for spawned processes? |
|
|
| Back to top |
|
| seanmc |
Posted: Thu Jun 04, 2009 2:17 pm |
|
|
|
User
Joined: 03 Aug 2007
Posts: 10
|
Hi Jacek,
This is really easy in Erlang. If you read your config file and assign the module name to a variable (as an atom):
Mod = read_config_file().
Then you can call its functions as normal, using the variable module name:
Mod:function1(),
Mod:function2().
Of course this assumes that any module you specify is loaded and that the functions called have the same interface.
The function names can also be variables, try in the shell:
(test@linux)1> M = io.
io
(test@linux)2> F = format.
format
(test@linux)3> M:F("~nHello~n~n").
Hello
ok
(test@linux)4>
(test@linux)4>
//Sean. |
|
|
| Back to top |
|
| jacek99 |
Posted: Thu Jun 04, 2009 5:18 pm |
|
|
|
User
Joined: 26 May 2009
Posts: 27
Location: Montreal, Canada
|
Ah, very cool.
So, the whole concept of behaviors in Erlang is really just sort of a compiler hint more than anything else?
It's not actually used at runtime when invoking methods on a particular module? |
|
|
| Back to top |
|
| jacek99 |
Posted: Thu Jun 04, 2009 8:01 pm |
|
|
|
User
Joined: 26 May 2009
Posts: 27
Location: Montreal, Canada
|
They way I did it is as a macro in an .hrl file:
-define(MODULE,module1)
Then just refer to it in the code
?MODULE:start()
?MODULE:stop()
etc.
if we want to test a different implementation, I just change the .hrl to point to a different module atom.
is this a proper Erlang-ish solution to the problem?
P.S. I wanted to write a Java-style factory first, but some instinct told me it's just not the right way to do it in Erlang.
 |
|
|
| Back to top |
|
| uwiger |
Posted: Fri Jun 05, 2009 11:28 am |
|
|
|
User
Joined: 03 Jul 2006
Posts: 604
Location: Sweden
|
jacek99 wrote: They way I did it is as a macro in an .hrl file:
-define(MODULE,module1)
Then just refer to it in the code
?MODULE:start()
?MODULE:stop()
etc.
if we want to test a different implementation, I just change the .hrl to point to a different module atom.
is this a proper Erlang-ish solution to the problem?
It is a fairly common way to do it, except that the macro ?MODULE is automatically defined as the current module. You should pick another name.
Sometimes, it can be appropriate to use the -import(Mod, Fns) directive (I know others would say that it's never appropriate.) The modules dict, orddict, and gb_dict, for example, have the same interface, but different performance characteristics. During early development, orddict might be best, since it is easy on the eyes when appearing in crash reports, etc. If it becomes obvious that it doesn't scale well enough for the problem, one would like to change to e.g. dict in one place only.
BR,
Ulf W |
|
|
| Back to top |
|
| uwiger |
Posted: Fri Jun 05, 2009 11:41 am |
|
|
|
User
Joined: 03 Jul 2006
Posts: 604
Location: Sweden
|
jacek99 wrote: Ah, very cool.
So, the whole concept of behaviors in Erlang is really just sort of a compiler hint more than anything else?
It's not actually used at runtime when invoking methods on a particular module?
That is only part of it. The -behaviour attribute indicates to the programmer as well as the linter what callback functions to expect in the module.
Mostly, though, a behaviour will include both a "specification" for the callbacks expected in the user-defined module, and the runtime framework for instantiating and calling the user-defined module.
That is, gen_server.erl is the module that defines the behaviour gen_server. It is called on by the linter at compile-time to list the expected callback functions, but it also has an API of its own, for the generic parts of the behaviour. In order to use a gen_server callback, you obviously have to call on the support functions in gen_server to create the framework in which the callback makes sense. |
|
|
| Back to top |
|
| jacek99 |
Posted: Fri Jun 05, 2009 1:40 pm |
|
|
|
User
Joined: 26 May 2009
Posts: 27
Location: Montreal, Canada
|
uwiger wrote:
It is a fairly common way to do it, except that the macro ?MODULE is automatically defined as the current module. You should pick another name.
Sorry, my mistake. That's just the name I used in the example, in the code we used a different name obviously. Thanks for validating my solution was the proper approach, much appreciated. |
|
|
| Back to top |
|
| jacek99 |
Posted: Fri Jun 05, 2009 1:44 pm |
|
|
|
User
Joined: 26 May 2009
Posts: 27
Location: Montreal, Canada
|
| Sorry, my mistake about MODULE. That's just the name I used in the example, in the code we used a different name obviously. Thanks for validating my solution was the proper approach, much appreciated. |
|
|
| Back to top |
|
|
|