I have a piece of erlang code which should read some values from a db and should support a couple of dbs. I wanted my code to be somehow not dependent from the db, so I implemented two different gen_servers that register both with the same atom (db_handler). I decide which version should be started reading the .app file.
The two gen_servers expose a common handle_call, so I can use in other parts of my application something like:
gen_server:call(db_handler, {do_something, "value1", "value2"})
This works, but still it is strongly coupled to the fact that each and any future implementation for a new db should be a gen_server.
I was thinking of using the ! operator and handle the command in the handle_info, but still I think that a better solution is possible (maybe passing through another module?).
Can somebody give me some insight on the better way to handle something like this in erlang?
For each db server add a common interface to abstract the call:
-module(db_server1).
...
do_something([Value1,Value2]) -> gen_server:call(db_handler, {do_something, "value1", "value2"}).
...
another one not using gen server
-module(db_server2).
...
do_something([Value1,Value2]) -> something_else({do_something, "value1", "value2"}).
...
create a new process (a gen_server :o) which receive as init parameter the param which is used to select the db server and store it in its state (for example db_server2),
for each do_something function, implement a function like:
do_something(Value1,Value2) -> gen_server:call(db_handler, {do_something, ["value1", "value2"]}).
...
handle_call({Func, Args}, _From, DB_server) ->
R = DB_server:F(Args),
{reply, R, DB_server}.
same thing for non blocking interfaces, using cast or equivalent
Each database driver could be a library module that exposes functions for your gen_server.
handle_call({do_something, Driver, Value1, Value2}, _From, State) ->
Reply = Driver:do_something(Value1, Value2),
{reply, Reply, State}.
Related
It seems like there are two ways to return errors in an async workflow: raise and Result.
let willFailRaise = async {
return raise <| new Exception("oh no!")
}
let willFailResult = async {
return Result.Error "oh no!"
}
For the caller, the handling is a bit different:
async {
try
let! x = willFailRaise
// ...
with error ->
System.Console.WriteLine(error)
}
async {
let! maybeX = willFailResult
match maybeX with
| Result.Ok x ->
// ...
| Result.Error error ->
System.Console.WriteLine(error)
}
My questions are:
What are the advantages / disadvantages of each approach?
Which approach is more idiomatic F#?
It depends on what kind of error we are talking about. Basically there are three kinds:
Domain errors (e.g. user provided invalid data, user with this email is already registered, etc.)
Infrastructure errors (e.g you can't connect to another microservice or DB)
Panics (e.g. NullReferenceExceptionor StackOverflowException etc.), which are caused by programmers' mistakes.
While both approaches can get the job done, usually your concern should be to make your code as self-documented and easy-to-read as possible. Which means the following:
Domain errors: definitely go for Result. Those "errors" are expected, they are part of your workflow. Using Result reflects your business rules in function's signature, which is very useful.
Infrastructure failures: it depends. If you have microservices, then probably those failures are expected and maybe it would be more convenient to use Result. If not -- go for exceptions.
Panics: definitely Exception. First of all, you can't cover everything with Result, you gonna need global exception filter either way. Second thing -- if you try to cover all possible panics - code becomes a nasty disaster extremely fast, that will kill the whole point of using Result for domain errors.
So really this has nothing to do with Async or C# interop, it's about code readability and maintainability.
As for C# iterop -- don't worry, Result has all the methods to help, like IsError and so on. But you can always add an extension method:
[<AutoOpen>]
module Utils =
type Result<'Ok, 'Error> with
member this.Value =
match this with
| Ok v -> v
| Error e -> Exception(e.ToString()) |> raise
This is one of the many aspects of F# programming that suffers from the mind-split at the core of the language and its community.
On one hand you have "F# the .NET Framework language" where exceptions are the mechanism for handling errors, on the other - "F# the functional programming language" that borrows its idioms from the Haskell side of the world. This is where Result (also known as Either) comes from.
The answer to the question "which one is idiomatic" will change depending who you ask and what they have seen, but my experience has taught me that when in doubt, you're better off using exceptions. Result type has its uses in moderation, but result-heavy programming style easily gets out of hand, and once that happens it's not a pretty sight.
Raise
Advantages
Better .NET interop as throwing exceptions is fairly common in .NET
Can create custom Exceptions
Easier to get the stack trace as it's right there
You probably have to deal with exceptions from library code anyways in most standard async operations such as reading from a webpage
Works with older versions of F#
Disadvantages:
If you aren't aware of it potentially throwing an exception, you might not know to catch the exception. This could result in runtime explosions
Result
Advantages
Any caller of the async function will have to deal with the error, so runtime explosions should be avoided
Can use railway oriented programming style, which can make your code quite clean
Disadvantages
Only available in F# 4.1 or later
Difficult for non-F# languages to use it
The API for Result is not comprehensive.
There are only the functions bind, map, and mapError
Some functions that would be nice to have:
bimap : ('TSuccess -> 'a) -> ('TError -> 'e) -> Result<'TSuccess,'TError> -> Result<'a, 'e>
fold : ('TSuccess -> 'T) -> ('TError -> 'T) -> Result<'TSuccess, 'TError> -> 'T
isOk
I was looking at some games made using erlang and I found one simple tic-tac-toe game here. I understood this game but I had a simple question that the person has used io:format() to show gamestate. So when I make a move like
gameclient:make_move(Player1, ChallengedPlayer, Message),
all I get in return is
{make_move,"player1",a3}
But I wanted to know that how can I retrieve the current gamestate on calling the function make_move/3.
I don't think using mnesia is a good option here.
Can anyone suggest a way to retrieve/return the gamestate rather than just printing it using io:format.
You may use ETS table for example
create table at startup:
ets:new(tik_tak_tab, [public, {read_concurrency, true}, ordered_set,named_table]).
store data into the table:
loop(Name) ->
receive
{ msg, Message } ->
ets:insert(tik_tak_tab, {state, Message}),
loop(Name)
end.
Make new function to retreive the state:
some_func() ->
case ets:lookup(tik_tak_tab, state) of
[{state, Message}] -> Message;
_ -> error
end.
_. There is also cheap way to use records
You may check detailed here
I have a very simple Erlang program:
-module(test).
-export([start/0]).
Code = "Z00887".
start() -> io:fwrite(Code).
And I have follows two errors:
c:/erl6.1/dev/test.erl:4: syntax error before: Code
c:/erl6.1/dev/test.erl:5: variable 'Code' is unbound
Could you please help me correctly using variables in my code.
You are defining a variable that is global to the module, which is not allowed. Remember, "variables" in Erlang are really "symbols", so there is no concept of a "global" constant across all functions or processes. The closest thing to this in Erlang would be a macro defined in the module, but if a value is only needed in one place and you want to name it then this must be done within the function definition.
Also, do not use io:fwrite/1 or io:format/1. The problem is the possible inclusion of escape characters in the string you are passing. For example, this causes an error: Code = "Wee~!", io:format(Code). and it will not be caught by the compiler.
The most common thing to do is define a variable within the function:
-module(foo).
-export([start/0]).
start() ->
Code = "Z00887",
io:fwrite("~p~n", [Code]).
You could also just use the value directly:
-module(foo).
-export([start/0]).
start() ->
io:fwrite("Z00887~n").
Or you could define a macro across the whole module:
-module(foo).
-export([start/0]).
-define(CODE, "Z00887").
start() ->
io:fwrite("~p~n", [?CODE]).
Or you could even define a stub function that returns what you want:
-module(foo).
-export([start/0]).
start() ->
io:fwrite("~p~n", [code()]).
code() -> "Z00887".
This last version is actually not as weird as it may seem at first. Very often when developing some code early on you will know you need a value somewhere that you will need to derive in some way, but don't want to worry about the details of it just yet. A stub function is an excellent way to hide the details of how you will do that in the future without writing macro code, variable definitions, etc. that you will have to remember to go back and change later. For example, the last example above will almost certainly change to something like this in the future:
-module(foo).
-export([start/0]).
start() ->
io:fwrite("~p~n", [code()]).
code() ->
{ok, Code} = some_init_module:get_code(),
Code.
Keep this in mind. It makes Erlang almost as prototype-friendly as Guile or Scheme.
I'm looking at the O'Reilly Erlang Programming book and there's an example that is run in the erlang shell that looks like this:
17> MS = ets:fun2ms(fun({Name,Country,Job}) when Job /= cook ->
[Country,Name] end).
[ ....an erlang match expression is returned.... ]
18> ets:select(countries, MS).
[[ireland,sean],[ireland,chris]]
However, when I do something similar in my code (not in the shell):
Fun = fun({Type,_,_,ObjectId,PlayerId}) when Type==player_atom, PlayerId==2 -> ObjectId end,
MatchFun = ets:fun2ms(Fun),
PlayerObjectId = ets:select(?roster_table, MatchFun),
I get FUBAR:
exit:{badarg,{ets,fun2ms,[function,called,with,real,'fun',should,be,transformed,with,parse_transform,'or',called,with,a,'fun',generated,in,the,shell]}}
(As an aside, I wonder why the error isn't 'function called with....' Probably so io:format("~p", TheErrorMessage) will line wrap?)
Anyway, I have abandoned select in favor of ets:foldl, since the latter works and - through exceptions in the fun - allows me to terminate the traversal when the first item is found. But, I'm still curious...
...wha? (I did some reading on parse_transform, and I'm new enough to erlang that I'm missing the connection.)
The badarg exception is symptom of a built-in function (or a pseudo function, as in this case) called with a wrong parameter. In this case, the ets:fun2ms/1 function.
Reading from the official documentation:
fun2ms(LiteralFun) -> MatchSpec
Pseudo function that by means of a parse_transform translates
LiteralFun typed as parameter in the function call to a match_spec.
With "literal" is meant that the fun needs to textually be written as
the parameter of the function, it cannot be held in a variable which
in turn is passed to the function).
((Please forgive me that I ask more than one question in a single thread. I think they are related.))
Hello, I wanted to know, what best practices exist in Erlang in regards to per-module precompiled data.
Example: I have a module that heavily operates on a priory know, veeery complex regular expressions. re:compile/2's documentations says: “Compiling once and executing many times is far more efficient than compiling each time one wants to match”. Since re's mp() datatype is in no way specified, and as such cannot be put at compile time if you want a target-independ beam, one has to compile the RegEx at runtime. ((Note: re:compile/2 is only an example. Any complex function to memoize would fit my question.))
Erlang's module (can) have an -on_load(F/A) attribute, denoting a method that should executed once when the module is loaded. As such, I could place my regexes to compile in this method and save the result in a new ets table named ?MODULE.
Updated after Dan's answer.
My questions are:
If I am understanding ets right, its data is saved in another process (differently form the process dictionary) and retrieving a value for an ets table is quite expensive. (Please prove me wrong, if I am wrong!) Should the content in ets be copied to the process dictionary for speedup? (Remember: the data is never being updated.)
Are there any (considerable) drawbacks of putting all data as one record (instead of many table items) into the ets/process dictionary?
Working example:
-module(memoization).
-export([is_ipv4/1, fillCacheLoop/0]).
-record(?MODULE, { re_ipv4 = re_ipv4() }).
-on_load(fillCache/0).
fillCacheLoop() ->
receive
{ replace, NewData, Callback, Ref } ->
true = ets:insert(?MODULE, [{ data, {self(), NewData} }]),
Callback ! { on_load, Ref, ok },
?MODULE:fillCacheLoop();
purge ->
ok
end
.
fillCache() ->
Callback = self(),
Ref = make_ref(),
process_flag(trap_exit, true),
Pid = spawn_link(fun() ->
case catch ets:lookup(?MODULE, data) of
[{data, {TableOwner,_} }] ->
TableOwner ! { replace, #?MODULE{}, self(), Ref },
receive
{ on_load, Ref, Result } ->
Callback ! { on_load, Ref, Result }
end,
ok;
_ ->
?MODULE = ets:new(?MODULE, [named_table, {read_concurrency,true}]),
true = ets:insert_new(?MODULE, [{ data, {self(), #?MODULE{}} }]),
Callback ! { on_load, Ref, ok },
fillCacheLoop()
end
end),
receive
{ on_load, Ref, Result } ->
unlink(Pid),
Result;
{ 'EXIT', Pid, Result } ->
Result
after 1000 ->
error
end
.
is_ipv4(Addr) ->
Data = case get(?MODULE.data) of
undefined ->
[{data, {_,Result} }] = ets:lookup(?MODULE, data),
put(?MODULE.data, Result),
Result;
SomeDatum -> SomeDatum
end,
re:run(Addr, Data#?MODULE.re_ipv4)
.
re_ipv4() ->
{ok, Result} = re:compile("^0*"
"([1-9]?\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.0*"
"([1-9]?\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.0*"
"([1-9]?\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.0*"
"([1-9]?\\d|1\\d\\d|2[0-4]\\d|25[0-5])$"),
Result
.
You have another option. You can precompute the regular expression's compiled form and refer to it directly. One way to do this is to use a module designed specifically for this purpose such as ct_expand: http://dukesoferl.blogspot.com/2009/08/metaprogramming-with-ctexpand.html
You can also roll your own by generating a module on the fly with a function to return this value as a constant (taking advantage of the constant pool): http://erlang.org/pipermail/erlang-questions/2011-January/056007.html
Or you could even run re:compile in a shell and copy and paste the result into your code. Crude but effective. This wouldn't be portable in case the implementation changes.
To be clear: all of these take advantage of the constant pool to avoid recomputing every time. But of course, this is added complexity and it has a cost.
Coming back to your original question: the problem with the process dictionary is that, well, it can only be used by its own process. Are you certain this module's functions will only be called by the same process? Even ETS tables are tied to the process that creates them (ETS is not itself implemented using processes and message passing, though) and will die if that process dies.
ETS isn't implemented in a process and doesn't have its data in a separate process heap, but it does have its data in a separate area outside of all processes. This means that when reading/writing to ETS tables data must be copied to/from processes. How costly this is depends, of course, on the amount of data being copied. This is one reason why we have functions like ets:match_object and ets:select which allow more complex selection rules before data is copied.
One benefit of keeping your data in an ETS table is that it can be reached by all processes not just the process which owns the table. This can make it more efficient than keeping your data in a server. It also depends on what type of operations you want to do on your data. ETS is just a data store and provides limited atomicity. In your case that is probably no problem.
You should definitely keep you data in separate records, one for each different compiled regular expression, as it will greatly increase the access speed. You can then directly get the re you are after, otherwise you will get them all and then search again after the one you want. That sort of defeats the point of putting them in ETS.
While you can do things like building ETS tables in on_load functions it is not a good idea for ETS tables. This is because an ETS is owned by a process and is deleted when the process dies. You never really know in which process the on_load function is called. You should also avoid doing things which can take a long time as the module is not considered to be loaded until it has completed.
Generating a parse transform to statically insert the result of compiling your re's directly into your code is a cool idea, especially if your re's are really that statically defined. As is the idea of dynamically generating, compiling and loading a module into your system. Again if your data is that static you could generate this module at compile time.
mochiglobal implements this by compiling a new module to store your constant(s). The advantage here is that the memory is shared across processes, where in ets it's copied and in the process dictionary it's just local to that one process.
https://github.com/mochi/mochiweb/blob/master/src/mochiglobal.erl