erlang mnesia - illegal record info
I am trying to have a function that ensures the table I need is already created and if not to create it. Here's the sample:
ensure_table_exists(Table, MnesiaTables, Nodes) ->
case lists:member(Table, MnesiaTables) of
true ->
throw(开发者_StackOverflow社区{error, db_might_have_already_been_created});
false ->
mnesia:create_table(Table, [{disc_copies, Nodes},
{attributes, record_info(fields, Table)}]),
ok
end.
The issue is that when compiling I get the error: illegal record info
.
It might have to do that record_info is resolved at compile time or that the second argument to record info should actually be a record that can be retrieved from the source code ?
Yes, all record related things including record_info/2
are resolved at compile time. This means that record and field names must be known at compile time. This is the reason for the compiler error.
I don't think your function is really too defensive in that what you are doing is signaling a more specific error. It would be another matter if you were to return {error, ...}
.
One last point is that if you mean to raise an exception you should not use throw/1
but instead use erlang:error/1
. throw
is intended for non-local return (caught with a catch
) while erlang:error
is intended for raising an exception. In many cases the result may be the same but the actual error value may be misleading (nocatch
). It is always better the clearer you can show your intention, which in this case is signaling an error.
P.S. Yes, I know that catch
also catches errors/exits as well. This was intentional. In a perfect world maybe catch
should only catch throws and try
only errors/exits.
Unfortunately record_info is not really a function even if it looks like one.
You can verify that by testing the following. Create a file:
-module(something).
-record(a, {}).
Start the Erlang shell:
> rr(something).
[a]
> record_info(fields, a).
[]
> A = a.
> record_info(fields, A).
* 2: illegal record info
So my recommendation would be to either use a macro or a specialised function for the record_info part.
To answer your original question. Use something like:
tables() ->
[?TABLE_MACRO(tablename),
?TABLE_MACRO(tablename2),
...].
where TABLE_MACRO is something like:
-define(TABLE_MACRO(Table), fun() ->
mnesia:create_table(Table, [{disc_copies, Nodes},
{attributes, record_info(fields, Table)}])
end).
and then have a function using something like the below.
[case CreateTable of
{aborted, {already_exists, _}} -> ok;
{atomic, ok} -> ok
end || CreateTable <- tables()].
Yuck! Can be cleaned up quite a bit, but hopefully you understand the general idea.
- Macro instead of variable use.
- Match on both {atomic, ok} and {aborted, {already_exists, _TableName}}
You might want to have a look to Ulf Wiger's exprecs.
Reading from the description:
The module is a parse transform allowing you to export records. The transform adds accessor functions for instantiating, inspecting and modifying records, without having to introduce compile-time dependencies between modules.
Said that, your function sounds a bit defensive to me. The following page explains why it's a bad habit to program defensively in Erlang:
http://www.erlang.se/doc/programming_rules.shtml#HDR11
精彩评论