The following code gives me an error: "syntax error before: Some_ets"
-module(tut).
-export([incr/1]).
Some_ets = ets:new(?MODULE, [bag]).
incr(X) ->
X+1.
But I am able to declare the ETS within a function, like:
-module(tut).
-export([incr/1]).
incr(X) ->
Some_ets = ets:new(?MODULE, [bag]),
X+1.
Can't I declare a ETS outside a function?
No - unlike other languages there isn't a concept of static initialization - there's no appropriate time for an Erlang system to execute that piece of code.
Erlang does have the concept of a parameterized module however, and that may be what you're after. Have a look here http://www.lshift.net/blog/2008/05/18/late-binding-with-erlang which is a good write up of that - it would allow you to instantiate an "instance" of your tut module bound to a given ets table and save passing around that handle explicitly in your module function calls.
Or if you are into OTP you could have the handle to the ets table passed around in the state variable:
init(_) ->
Some_ets = ets:new(?MODULE, [bag]),
{ok, Some_ets}.
and then use it in your handle_call methods:
get_ets_handle() ->
gen_server:call(?MODULE, {getETSHandle}, infinity).
handle_call({getETSHandle}, _From, Some_ets) ->
{reply, Some_ets, Some_ets}.
You can't do variable assignments like that in a module. See here.
Related
I'm trying to meck out a call to application:get_env, but I'm testing a function that calls it with two different sets of arguments.
I setup two separate meck:expect calls like this, but when the function I'm testing tries to call application:get_env(my_app, my_param_one) it fails and throws error:function_clause with undefined.
meck:expect(application, get_env, fun(my_app, my_param_one) -> {ok, "my_value_one"} end),
meck:expect(application, get_env, fun(my_app, my_param_two) -> {ok, "my_value_two"} end),
How can I meck out the same function, with differents sets of parameter values?
The second meck is overwriting the first.
Whenever you define a function in Erlang by pattern-matching on different sets of values, you separate each set of patterns with a semicolon, like this:
-module(sample).
-export([create_greeting/2]).
create_greeting("Grant", _Greeting) -> io:format("Good day sir!");
create_greeting(Name, Greeting) -> io:format("~s, ~s!", [Greeting, Name]).
Similarly, when you setup your meck statements, define the function once, but separate each set of patterns/arguments with a semicolon, like this:
meck:expect(application, get_env, fun(my_app, my_param_one) -> {ok, "my_value_one"};
(my_app, my_param_two) -> {ok, "my_value_two"}
end),
I'm trying to write and compile a custom behaviour in Erlang.
I cannot find any clear documentation on how to compile this behaviour.
-module(bla).
-export([start_link/0,behaviour_info/1]).
behaviour_info(callbacks)->
[{init,1}];
behaviour_info(_Other)->
undefined.
%% -callback init(Args :: term()) ->
%% {ok, State :: term()} | {ok, State :: term(), timeout()} |
%% {stop, Reason :: term()} | ignore.
start_link()->
init([]).
my command for comiling is :
erlc.exe .\src\bla.erl
resulting:
bla.erl:24: function init/1 undefined
Anyone an idea on writing and compiling behaviours in erlang, please? any links?
Defining behaviour callbacks results in an obligation towards your implementation of callback module. In erlang, modules are just function containers, not classes nor interfaces. Behaviours are based on runtime module name resolution Mod:fun(). OTP gen_server (check it) keeps its callback module name after you pass it in: gen_server:start_link(CallbackModuleName, Args, Opts) and here is code for applying callback init/1:
init_it(Starter, Parent, Name0, Mod, Args, Options) ->
Name = name(Name0),
Debug = debug_options(Name, Options),
case catch Mod:init(Args) of
{ok, State} ->
proc_lib:init_ack(Starter, {ok, self()}),
loop(Parent, Name, State, Mod, infinity, Debug);
{ok, State, Timeout} ->
proc_lib:init_ack(Starter, {ok, self()}),
loop(Parent, Name, State, Mod, Timeout, Debug);
...
It's applying init/1 of passed callback module kept in Mod parameter, gets its last value, do what you want and keep going (or not, depends on that last value).
Assume we have module bla_impl which looks like this:
-module(bla_impl).
-behaviour(bla).
-export([init/1, start_link/0]).
start_link() -> bla:start_link(?MODULE). %% macro ?MODULE is resolved to bla_impl
init(Args) -> ... .
And now you need to say in bla which module you use by:
-module(bla).
-export([start_link/1]).
start_link(Mod) -> Mod:init([]).
or maybe better solution is to read it from configuration:
-module(bla).
-export([start_link/0]).
start_link() ->
Mod = application:get_env(bla_app, callback_module),
Mod:init([]),
...
There is many ways for doing so.
As you see there is no magic here. This would work even without -behaviour(bla) nor specified callback with -callback. This is just an information for compiler, tools and documentation.
From erlang documentation: Behaviours
And btw. start_link function should spawn another process and link to it.
start_link(Mod) ->
spawn_link(Mod, init, [[]]).
I have skimmed through the Mochiweb code, but have not found any sign of the State variable.
Does something similar to gen_server's State variable exist in Mochiweb?
I need to store some small amount of state-related server-side (not session-related) data on the server and I do not want to use ETS or Mnesia for that.
I think you have somewhat a misunderstanding of what gen_server state is.
First, let me explain briefly how mochiweb works.
Mochiweb doesn't produce a gen_server process per client. Instead, it just spawns a new process using proc_lib:spawn/3 and creates a parametrized module, which is, basically, a tuple of the following kind:
{mochiweb_request, #Port<0.623>, get, "/users", {1, 1}, []}
which is
{mochiweb_request, Socket, Method, RawPath, HTTPVersion, Headers}
This tuple is used as an argument to a function that you pass as a loop parameter to mochiweb_http:start/1. So, when this "loop" function is called, it will look like this:
handle_request(Req) ->
%% The pattern matching below just shows what Req really is
{mochiweb_request, _, _, _, _, _} = Req,
...
Now, to explanation of gen_server state.
Basically, gen_server is a process with approximately the following structure. Of course, IRL it's more complicated, but this should give you the general idea:
init(Options)
State = ...
loop(Module, State).
loop(Module, State)
NewState = receive
{call, Msg, From} -> Module:handle_call(Msg, From, State)
{cast, Msg} -> Module:handle_cast(Msg, State)
Info -> Module:handle_info(Info, State)
end,
loop(Module, NewState).
So, state is just an argument that you drag through all the function calls and change inside your loop. It doesn't actually matter if your process is a gen_server or not, it doesn't have what lifetime it has. In the following example the term [1, 2, 3] is a state too:
a() ->
b([1, 2, 3], now()).
b(State, Timestamp) ->
Result = do_something(Timestamp)
c(State, Result).
c(State, Payload) ->
exit({State, Payload}).
Now, back to mochiweb.
If you need to create a state of your own, you can just add an extra function argument:
handle_request(Req) ->
User = Req:get(path),
UserData = load_user_data(User),
handle_request(Req, UserData).
handle_request(Req, UserData) ->
...
Now UserData is a state too. You can loop this process, or let it respond and end right away – but you won't lose UserData as long as you pass it as an argument.
Finally, if you really want to make this process a gen_server (which is really unreasonable in most cases), you can use gen_server:enter_loop/3 function that will make your current process a gen_server. And The 3rd argument of this function will be your state that will be stored inside the started gen_server.
I want to extend gen_server (create a gen_server_extra) with some additional functionality. The requirements are:
The gen_server_extra processes should behave like a regular gen_server's. E.g, they should accept calls via gen_server:call, integrate with SASL, fit OTC supervision tree, etc.
gen_server_extra processes should have an additional functionality, provided by gen_server_extra. That basically means some of the messages will be handled by gen_server_extra code, without passing them to the callback module. The rest of the messages are passed to callback module as is.
gen_server_extra functionality requires its own state which should be hidden from the callback module.
What is the simplest approach to do that?
The best, most modular approach would be to implement a new behavior in a module (e.g. gen_ext_server) and wrap the gen_server behavior from there.
First, make sure your behavior is identical to gen_server:
-module(gen_ext_server).
-behavior(gen_server).
% Exports...
behaviour_info(Type) -> gen_server:behaviour_info(Type).
Implement all callbacks needed for gen_server, keep the name of the callback module that implements your behavior in your state:
init([Mod|ExtraArgs]) ->
% ...
ModState = Mod:init(ExtraArgs),
#state{mod = Mod, mod_state = ModState, internal = [...]}
Then, in each gen_server callback, implement your behavior and then call the callback module if needed:
handle_call(internal, _From, State) ->
% Do internal stuff...
{reply, ok, State};
handle_call(Normal, From, State = #state{mod = Mod, mod_state = ModState}) ->
case Mod:handle_call(Normal, From, ModState) of
{reply, Reply, NewState} ->
{reply, Reply, #state{mod_state = NewState};
... ->
...
end.
Implement similar functionality for handle_cast/2, handle_info/2, terminate/1 etc.
well, i would not call it customization, but rather a new behavior. You need to define your own behavior. A tutorial which will take you through this is found at trapexit.org.
However, the requirements are not very proper.
The main essence of giving the call back functions access to the server state is to write normal sequential code manipulating the state of your application when and where you want without interrupting the concurrency details.
Otherwise if that is the way to go, implement your own behavior.
I want to call xyz with the name of a function to be invoked.
-module(sample).
-export([xyz/1]).
xyz(Name) -> Name().
p() -> "you called p".
g() -> "you called g".
But I get the following error:
1> c(sample.erl).
./sample.erl:6: Warning: function p/0 is unused
./sample.erl:7: Warning: function g/0 is unused
{ok,sample}
2> sample:xyz('p').
** exception error: bad function p
in function sample:xyz/1
3>
It is correct that you have to export p and g. You can then use apply/3 to call it.
erlang:apply(sample, p, []).
Only fun-values are usable with the Fun(...) syntax. You are passing in an atom-value. An atom is a 'bad function' as the error message go. You could do something similar to
xyz(p) -> fun p/0;
xyz(g) -> fun g/0.
Then go ahead and call
Fun = xyz(p),
Fun()
-module(sample).
-export([xyz/1, p/0, g/0]).
xyz(Name) -> ?MODULE:Name().
p() -> "you called p".
g() -> "you called g".
1> sample:xyz(p).
"you called p"
Pattern match is the idiom to use:
-module(sample).
-export([xyz/1]).
xyz(p) -> p();
xyz(q) -> g().
p() -> "you called p".
g() -> "you called g".
If you want to be dynamic you can use a gen_event server.
Essentially what this is is a server that holds a state which consists of key/function pair like so:
[{p, #func1},
{g, #func2},
{..., ...},
...]
You can then essentially bind events to functions. (there is, needless to say, a bit more to it than that.
The easiest way to do is to try exporting p and g along with xyz.
-export([xyz/1, p/0,g/0]).
After exporting the function p and g can be called as follows :
1> sample:xyz(fun sample:p/0).
"you called p"
2> sample:xyz(fun sample:g/0).
"you called g"
Another way to look at it is that (depending on the problem you're solving) dynamic calls to functions isn't necessarily the right approach. Given that processes and message passing are the way you organize your code in Erlang since it's a "concurrency oriented language", maybe you could just use message passing with a selective receive rather than mimicking idioms of a sequential language? Send a message for what you want and get the custom reply based on that. It's about the result of each function, not the function itself, after all. (Plus there's the flexibility and scalability of message passing, etc.)
Although processes aren't totally free compared to calling from a library module, Erlang-level processes are dirt cheap (especially if the message communication is within the same node). They're not OS-level processes. The overhead would be comparable (or better) to dynamic function calls and object instantiation in heavier scripting languages.