I'm implementing a crash function in a GenServer to test the behavior of the supervisor and registry that will manage this process. Work is done in Elixir but I believe it may also concern Erlang.
I could have called raise() but in the first place I implemented 1/0 as the reason for crash. The compiler being a smart guy, for the following code:
def handle_cast(:crash, state) do
a = 1 / 0
{:noreply, state}
end
I got the warning:
warning: this expression will fail with ArithmeticError
lib/xyz/worker.ex:47
Fair. After all, even old C or C++ compilers were able to detect this kind of things. I tried a library call replacing a = 1 / 0 by a = 1 / :math.sin(0). Same warning. My curiosity woke up and I tried different things with the same outcome. Actually, it looks like this is not so easy to fool the compiler! Eventually, I put:
a = 1 / Enum.reduce([0, 1, -1], 0, fn(n, acc) -> n+acc end)
and got a different warning:
warning: the result of the expression is ignored (suppress the warning by assigning the expression to the _ variable)
lib/xyz/worker.ex:50
line 50 being a = 1 / Enum.reduce(...).
I spent a couple of hours trying different things with always getting either warning.
I believe the first one is raised because the compiler is able to precalculate the result out of constant arguments and of function type and inline eventually the operation 1 / 0.
Yet I don't understand the second warning. In one of the tests, I wrote :
def handle_cast(:crash, state) do
a = 1 / Enum.reduce([0, 1, -1], 0, fn(n, acc) -> n+acc end)
# {:noreply, state}
end
which actually suppresses the warning, but I really don't understand why.
NB.1: Versions:
maurice#mickey> elixir -v
Erlang/OTP 20 [erts-9.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Elixir 1.6.1 (compiled with OTP 19)
NB.2: I'm aware of this question, yet I don't think the reply applies here.
For the time being, I'll be calling raise(...)...
Short version
The warning is actually telling you what to do: replace a = ... with _ = ....
Long version
In your examples at hand you assign the result of the operation to a variable called a. The compile notices that you never use that variable again, so it complains about it.
Elixir knows a "special" variable for that case called _. When doing _ = ... or def my_function(_, second_paramter) you basically tell the compiler:
I don't want to use that value, so please don't complain
To provide more information about the ignored value, you can also prefix a variable with an underscore (_), which serves the same purpose. In your case that could be _a = ....
This is mainly useful when ignoring arguments in a function, without leaving the reader to guess what that argument was about. So def get(:thing, _) could become def get(:thing, _opts).
Then you asked why the commented out version didn't produce that error. The answer to that lies in the fact that the return value of a function is equal to the last statement of that function.
So this function
def my_function do
1
2
3
end
returns 3, while this function
def my_function do
:a
:b
end
returns :b. As such in your example
def handle_cast(:crash, state) do
a = 1 / Enum.reduce([0, 1, -1], 0, fn(n, acc) -> n+acc end)
# {:noreply, state}
end
You commented out the # {:noreply, state} tuple and the a = ... statement becomes the last one in the function. Since now you create the variable a and evaluate it as part of the "return", the compiler stops complaining.
On the other hand, a fair case could be made that a variable assignment in the last line of a function is useless. So this might actually warrant a low priority issue on GitHub.
Fool the compiler till the end, reassign state variable:
def handle_cast(:crash, state) do
state = Enum.reduce([0, 1, -1], 0, fn(n, acc) ->
n + acc
end)
{:noreply, state}
end
That way the compiler will think state assignment is necessary (since it’s used as a return value.)
Related
I am learning Erlang and one of the problems as per Joe's book states
The function even(X) should return true if X is an even integer and
otherwise false. odd(X) should return true if X is an odd integer.
The way I solve this is
-module(math_functions).
%% API
-export([even/1, odd/1]).
even(Integer) -> (Integer >= 0) and (Integer rem 2 =:= 0).
odd(Integer) -> (Integer >= 1) and (Integer rem 2 =/= 0).
and run this as
Eshell V6.2 (abort with ^G)
1> math_functions:odd(13).
true
2> math_functions:odd(-13).
false
3> math_functions:odd(1).
true
4> math_functions:even(1).
false
5> math_functions:even(2).
true
6> math_functions:even(-2).
false
7>
The question I have is if there are better ways to do this
Thanks
You could use guards to limit yourself to integers greater than or equal to zero, and then simply check the least-significant bit as suggested in the comment to your question. You can also define odd/1 in terms of even/1:
even(X) when X >= 0 -> (X band 1) == 0.
odd(X) when X > 0 -> not even(X).
The guards are part of the function-head, so if you call even(-1) it will fail to match in exactly the same way as if you called even(1, 2) (i.e. with the wrong number of arguments).
Answer to Daydreamer comment about Steve answer.
When you write a function, a frequent usage in erlang is to code only the "success" cases and let crash the unsuccessful cases (I'll come back later to explain why it is important).
Another criteria, valid for any language, is to avoid surprise when someone use or read your code.
In one of your comment you say that the odd and even functions you want to write are limited to positive or null integers (I won't discuss this choice, and at least the odd and even functions are limited to integers). This means that you have to ask yourself a first question: what is the behavior of my function if it is called with a bad parameter.
First choice: let it crash this the Steve proposition: the function works only with the correct arguments. I always prefer this solution. The only exception is if I do not master the input parameters, for example if they come directly from a file, a user interface ... Then I prefer the third choice.
Second choice: return a result this is your choice: you return false. From a logic point of view, for odd and even function, returning false is valid: is something is not true, it is false :o). I don't like this solution for 2 reasons. The first one is that it is not something you can generalize easily to something else than boolean answer. The second and more important to me, is that it may surprise the user. When the function odd(N) return false, it is reasonable to think that N is even, while in this case odd(-2) and even(-2) will both return false.
third choice: return a tagged result this is something you see very often in erlang: a function return either {ok,Value} or {Error,Term}. doing this you let the choice to the calling function to manage or not a bad arguments errors. the Error variable allows you to have explicit error messages, useful for debug and also user interface. In your example the code becomes:
even(X) when is_integer(X), X >= 0 -> {ok,(X band 1) == 0};
even(X) -> {illegal_param,X}.
odd(X) when is_integer(X), X >= 0 -> {ok,(X band 1) == 1};
odd(X) -> {illegal_param,X}.
When programming, it is important to detect error as soon as possible, in erlang it is even more important. If one process does not detect (and the simplest detection is crash) and error and propagate some invalid information through messages, it may be very difficult to find the root cause of a problem, ignoring which process (maybe died) issued this message. Coding only the success cases is an easy way to detect problems as soon as possible.
Find the no if even
%functions that manipulate functions are called higher-order %functions, and the data type that represents a function in Erlang is %called a fun. here in below example you see FUNCTIONS THAT HAVE %FUNCTIONS AS THEIR ARGUMENTS
% K is an example list
1> K=[4,5,6,8,10].
[4,5,6,8,10]
% Use lisst:filter to perform no/2 and filter if rem=0
2> lists:filter(fun(J)->(J rem 2)=:=0 end, K).
[4,6,8,10]
Another way:
% Function to check even
22> Checkeven=fun(U)->(U rem 2)=:=0 end.
#Fun<erl_eval.7.126501267>
23> Checkeven(5).
false
% Define a test list
25> K=[1,2,3,4,5].
[1,2,3,4,5]
% Use lists filter to apply Checkeven func to all elements of k
26> lists:filter(Checkeven,K).
[2,4]
%Using List comprehension
42> K.
[1,2,3,4,5]
% For all elements of K check remainder of elem/2 is zero
43> [(S rem 2=:=0) || S<-K].
[false,true,false,true,false]
When reading rabbitmq's rabbit.erl,it contain hipe compilation related code.
hipe_compile() ->
Count = length(?HIPE_WORTHY),
io:format("HiPE compiling: |~s|~n |",
[string:copies("-", Count)]),
T1 = erlang:now(),
PidMRefs = [spawn_monitor(fun () -> [begin
{ok, M} = hipe:c(M, [o3]),
io:format("#")
end || M <- Ms]
end) ||
Ms <- split(?HIPE_WORTHY, ?HIPE_PROCESSES)],
[receive
{'DOWN', MRef, process, _, normal} -> ok;
{'DOWN', MRef, process, _, Reason} -> exit(Reason)
end || {_Pid, MRef} <- PidMRefs],
T2 = erlang:now(),
io:format("|~n~nCompiled ~B modules in ~Bs~n",
[Count, timer:now_diff(T2, T1) div 1000000]).
But there is no explanation about hipe in the erlang's reference doc. What's the meaning of 'o3'?
(emacs#chen-yumatoMacBook-Pro.local)51> hipe:c(xx_reader,[o3]).
{ok,xx_reader}
After I use hipe:c as above, No new compiled file can be found the in the pwd() directory?
Where it is?
o3 indicates the optimization level used by the compiler. There're also levels o0, o1, o2. Details of the levels are as follows:
o1 = [inline_fp,pmatch,peephole],
o2 = [icode_range,icode_ssa_const_prop,icode_ssa_copy_prop,icode_type,
icode_inline_bifs,rtl_lcm,rtl_ssa,rtl_ssa_const_prop,spillmin_color,
use_indexing,remove_comments,concurrent_comp,binary_opt] ++ o1,
o3 = [{regalloc,coalescing},icode_range] ++ o2.
You can use hipe:help_option(Option) to further investigate the meanings of different options. For example,
3> hipe:help_option(regalloc).
regalloc - Select register allocation algorithm. Used as {regalloc, METHOD}.
Currently available methods:
naive - spills everything (for debugging and testing)
linear_scan - fast; not so good if few registers available
graph_color - slow, but gives OK performance
coalescing - slower, tries hard to use registers
optimistic - another variant of a coalescing allocator
ok
4> hipe:help_option(icode_range).
icode_range - Performs integer range analysis on the Icode level
ok
I think HiPE is JIT compilation, just as the one used in Java. The native parts are available only in runtime, so there should be no explicit representation in your file system.
Also, hipe:c do require a .beam file is present. For example, if you create a test.erl with some stuff, and without compiling it to a .beam file, call hipe:c directly will lead to an error:
1> hipe:c(test, [o3]).
<HiPE (v 3.9.3)> EXITED with reason {cant_find_beam_file,test} #hipe:419
=ERROR REPORT==== 29-Nov-2012::17:03:02 ===
<HiPE (v 3.9.3)> Error: [hipe:418]: Cannot find test.beam file.** exception error: {hipe,419,{cant_find_beam_file,test}}
in function hipe:beam_file/1 (hipe.erl, line 419)
in call from hipe:c/2 (hipe.erl, line 313)
2> c(test).
{ok,test}
3> hipe:c(test, [o3]).
{ok,test}
There is some in erlang's doc. See here. But the doc is not much indeed. The index page of HiPE only updated recently.
Also, you can check some help in erlang shell.
> hipe:help().
> hipe:help_options().
> hipe:help_option(Option).
In most applications, its hard to avoid the need to query large amounts of information which a user wants to browse through. This is what led me to cursors. With mnesia, cursors are implemented using qlc:cursor/1 or qlc:cursor/2. After working with them for a while and facing this problem many times,
11> qlc:next_answers(QC,3).
** exception error: {qlc_cursor_pid_no_longer_exists,<0.59.0>}
in function qlc:next_loop/3 (qlc.erl, line 1359)
12>
It has occured to me that the whole cursor thing has to be within one mnesia transaction: executes as a whole once. like this below
E:\>erl
Eshell V5.9 (abort with ^G)
1> mnesia:start().
ok
2> rd(obj,{key,value}).
obj
3> mnesia:create_table(obj,[{attributes,record_info(fields,obj)}]).
{atomic,ok}
4> Write = fun(Obj) -> mnesia:transaction(fun() -> mnesia:write(Obj) end) end.
#Fun<erl_eval.6.111823515>
5> [Write(#obj{key = N,value = N * 2}) || N <- lists:seq(1,100)],ok.
ok
6> mnesia:transaction(fun() ->
QC = cursor_server:cursor(qlc:q([XX || XX <- mnesia:table(obj)])),
Ans = qlc:next_answers(QC,3),
io:format("\n\tAns: ~p~n",[Ans])
end).
Ans: [{obj,20,40},{obj,21,42},{obj,86,172}]
{atomic,ok}
7>
When you attempt to call say: qlc:next_answers/2 outside a mnesia transaction, you will get an exception. Not only just out of the transaction, but even if that method is executed by a DIFFERENT process than the one which created the cursor, problems are bound to happen.
Another intresting finding is that, as soon as you get out of a mnesia transaction, one of the processes which are involved in a mnesia cursor (apparently mnesia spawns a process in the background), exits, causing the cursor to be invalid. Look at this below:
-module(cursor_server).
-compile(export_all).
cursor(Q)->
case mnesia:is_transaction() of
false ->
F = fun(QH)-> qlc:cursor(QH,[]) end,
mnesia:activity(transaction,F,[Q],mnesia_frag);
true -> qlc:cursor(Q,[])
end.
%% --- End of module -------------------------------------------
Then in shell, i use that method:
7> QC = cursor_server:cursor(qlc:q([XX || XX <- mnesia:table(obj)])).
{qlc_cursor,{<0.59.0>,<0.30.0>}}
8> erlang:is_process_alive(list_to_pid("<0.59.0>")).
false
9> erlang:is_process_alive(list_to_pid("<0.30.0>")).
true
10> self().
<0.30.0>
11> qlc:next_answers(QC,3).
** exception error: {qlc_cursor_pid_no_longer_exists,<0.59.0>}
in function qlc:next_loop/3 (qlc.erl, line 1359)
12>
So, this makes it very Extremely hard to build a web application in which a user needs to browse a particular set of results, group by group say: give him/her the first 20, then next 20 e.t.c. This involves, getting the first results, send them to the web page, then wait for the user to click NEXT then ask qlc:cursor/2 for the next 20 and so on. These operations cannot be done, while hanging inside a mnesia transaction !!! The only possible way, is by spawning a process which will hang there, receiving and sending back next answers as messages and receiving the next_answers requests as messages like this:
-define(CURSOR_TIMEOUT,timer:hours(1)).
%% initial request is made here below
request(PageSize)->
Me = self(),
CursorPid = spawn(?MODULE,cursor_pid,[Me,PageSize]),
receive
{initial_answers,Ans} ->
%% find a way of hidding the Cursor Pid
%% in the page so that the subsequent requests
%% come along with it
{Ans,pid_to_list(CursorPid)}
after ?CURSOR_TIMEOUT -> timedout
end.
cursor_pid(ParentPid,PageSize)->
F = fun(Pid,N)->
QC = cursor_server:cursor(qlc:q([XX || XX <- mnesia:table(obj)])),
Ans = qlc:next_answers(QC,N),
Pid ! {initial_answers,Ans},
receive
{From,{next_answers,Num}} ->
From ! {next_answers,qlc:next_answers(QC,Num)},
%% Problem here ! how to loop back
%% check: Erlang Y-Combinator
delete ->
%% it could have died already, so we be careful here !
try qlc:delete_cursor(QC) of
_ -> ok
catch
_:_ -> ok
end,
exit(normal)
after ?CURSOR_TIMEOUT -> exit(normal)
end
end,
mnesia:activity(transaction,F,[ParentPid,PageSize],mnesia_frag).
next_answers(CursorPid,PageSize)->
list_to_pid(CursorPid) ! {self(),{next_answers,PageSize}},
receive
{next_answers,Ans} ->
{Ans,pid_to_list(CursorPid)}
after ?CURSOR_TIMEOUT -> timedout
end.
That would create a more complex problem of managing process exits, tracking / monitoring e.t.c. I wonder why the mnesia implementers didnot see this !
Now, that brings me to my questions. I have been walking around the web for solutions and you could please check out these links from which the questions arise: mnemosyne, Ulf Wiger's Solution to Cursor Problems, AMNESIA - an RDBMS implementation of mnesia.
1. Does anyone have an idea on how to handle mnesia query cursors in a different way from what is documented, and is worth sharing ?
2. What are the reasons why mnesia implemeters decided to force the cursors within a single transaction: even the calls for the next_answers ?
3. Is there anything, from what i have presented, that i do not understand clearly (other than my bad buggy illustration code - please ignore those) ?
4. AMNESIA (on section 4.7 of the link i gave above), has a good implementation of cursors, because the subsequent calls for the next_answers, do not need to be in the same transaction, NOR by the same process. Would you advise anyone to switch from mnesia to amnesia due to this and also, is this library still supported ?
5. Ulf Wiger , (the author of many erlang libraries esp. GPROC), suggests the use of mnesia:select/4. How would i use it to solve cursor problems in a web application ? NOTE: Please do not advise me to leave mnesia and use something else, because i want to use mnesia for this specific problem. I appreciate your time to read through all this question.
The motivation is that transaction grabs (in your case) read locks.
Locks can not be kept outside of transactions.
If you want, you can run it in a dirty_context, but you loose the
transactional properties, i.e. the table may change between invocations.
make_cursor() ->
QD = qlc:sort(mnesia:table(person, [{traverse, select}])),
mnesia:activity(async_dirty, fun() -> qlc:cursor(QD) end, mnesia_frag).
get_next(Cursor) ->
Get = fun() -> qlc:next_answers(Cursor,5) end,
mnesia:activity(async_dirty, Get, mnesia_frag).
del_cursor(Cursor) ->
qlc:delete_cursor(Cursor).
I think this may help you :
use async_dirty instead of transaction
{Record,Cont}=mnesia:activity(async_dirty, fun mnesia:select/4,[md,[{Match_head,[Guard],[Result]}],Limit,read])
then read next Limit number of records:
mnesia:activity(async_dirty, fun mnesia:select/1,[Cont])
full code:
-record(md,{id,name}).
batch_delete(Id,Limit) ->
Match_head = #md{id='$1',name='$2'},
Guard = {'<','$1',Id},
Result = '$_',
{Record,Cont} = mnesia:activity(async_dirty, fun mnesia:select/4,[md,[{Match_head,[Guard],[Result]}],Limit,read]),
delete_next({Record,Cont}).
delete_next('$end_of_table') ->
over;
delete_next({Record,Cont}) ->
delete(Record),
delete_next(mnesia:activity(async_dirty, fun mnesia:select/1,[Cont])).
delete(Records) ->
io:format("delete(~p)~n",[Records]),
F = fun() ->
[ mnesia:delete_object(O) || O <- Records]
end,
mnesia:transaction(F).
remember you can not use cursor out of one transaction
Note: This is a sequel to my previous question about powersets.
I have got a nice Ruby solution to my previous question about generating a powerset of a set without a need to keep a stack:
class Array
def powerset
return to_enum(:powerset) unless block_given?
1.upto(self.size) do |n|
self.combination(n).each{|i| yield i}
end
end
end
# demo
['a', 'b', 'c'].powerset{|item| p item} # items are generated one at a time
ps = [1, 2, 3, 4].powerset # no block, so you'll get an enumerator
10.times.map{ ps.next } # 10.times without a block is also an enumerator
It does the job and works nice.
However, I would like to try to rewrite the same solution in Erlang, because for the {|item| p item} block I have a big portion of working code already written in Erlang (it does some stuff with each generated subset).
Although I have some experience with Erlang (I have read all 2 books :)), I am pretty confused with the example and the comments that sepp2k kindly gave me to my previous question about powersets. I do not understand the last line of the example - the only thing that I know is that is is a list comprehension. I do not understand how I can modify it to be able to do something with each generated subset (then throw it out and continue with the next subset).
How can I rewrite this Ruby iterative powerset generation in Erlang? Or maybe the provided Erlang example already almost suits the need?
All the given examples have O(2^N) memory complexity, because they return whole result (the first example). Two last examples use regular recursion so that stack raises. Below code which is modification and compilation of the examples will do what you want:
subsets(Lst) ->
N = length(Lst),
Max = trunc(math:pow(2, N)),
subsets(Lst, 0, N, Max).
subsets(Lst, I, N, Max) when I < Max ->
_Subset = [lists:nth(Pos+1, Lst) || Pos <- lists:seq(0, N-1), I band (1 bsl Pos) =/= 0],
% perform some actions on particular subset
subsets(Lst, I+1, N, Max);
subsets(_, _, _, _) ->
done.
In the above snippet tail recursion is used which is optimized by Erlang compiler and converted to simple iteration under the covers. Recursion may be optimized this way only if recursive call is the last one within function execution flow. Note also that each generated Subset may be used in place of the comment and it will be forgotten (garbage collected) just after that. Thanks to that neither stack nor heap won't grow, but you also have to perform operation on subsets one after another as there's no final result containing all of them.
My code uses same names for analogous variables like in the examples to make it easier to compare both of them. I'm sure it could be refined for performance, but I only want to show the idea.
Is it possible to know the name of a function in itself ?
a_function()->
io:format("I am ~p!", [????]). % What to use here?
Use the macro ?FUNCTION_NAME to get the name of the current function as an atom, and ?FUNCTION_ARITY to get the arity as an integer.
Example:
-module(test).
-export([a_function/2]).
a_function(_Foo, _Bar) ->
io:write("I am ~p/~p!",[?FUNCTION_NAME, ?FUNCTION_ARITY]).
1> c(test).
{ok,test}
2> test:a_function(a, b).
I am a_function/2!
This was implemented in EEP-0045.
For Erlang Versions 18 and Older
In older Erlang versions, there's no simple way to get the current function name at compile time. You can however retrieve it at runtime:
{current_function, {M, F, A}} = process_info(self(), current_function)
Where A is the arity (number of arguments), not the actual arguments. The first argument to process_info/2 is a process ID which can be either the current process (self()) or an other process. For example:
1> process_info(self(), current_function).
{current_function,{erl_eval,do_apply,5}}
Note however, that while this would be functionally equivalent to the ?FUNCTION_NAME macro, it's much slower because it is evaluated in runtime.
at runtime, you could throw an exception and check the top of the stacktrace.
foo() ->
catch throw(away),
[{Module, Fun, Arity} | _] = erlang:get_stacktrace(),
io:format("I am ~p:~p/~p!~n",[Module, Fun, Arity]).