I should mention that I like the immutable variables in Erlang. I only find them to be an annoyance when I want to write a quick program. In this sense they are sort of like static types in other languages; they force you to design your program before you start coding. The sort of complaints I've read about non-destructive variable updates (e.g., writing tests) seem to reinforce this view.
A quick example of using wat: you want to benchmark various checksum functions and prove the results are evenly distributed for a given set of inputs. We can benchmark a version using arrays and another using NIF's.
The array version:
-module(csum). -export([start/2]). -export([loop/3]). start(Hash,File) -> {ok, Fh} = file:open(File, [ binary, read, read_ahead, raw ]), {MicroSec, L} = timer:tc( ?MODULE, loop, [Fh, Hash, array:new([3, {default,0}])] ), T = lists:sum(L), P = [ N / T * 100 || N <- L ], {{elapsed_time, MicroSec / 1000000}, {result, L}, {total, T}, {perc, P}}. loop(Fh, Hash, Count) -> case file:read_line(Fh) of eof -> array:to_list(Count); {error, Error} -> io:format("error:~p~n", [Error]); {ok, Line} -> N = erlang:Hash(Line) rem array:size(Count), V = array:get(N, Count), loop(Fh, Hash, array:set(N, V+1, Count)) end.
The NIF version:
-module(scum). -export([start/2]). -export([loop/3]). start(Hash, File) -> wat:init(), {ok, Fh} = file:open(File, [ binary, read, read_ahead, raw ]), {MS, A} = timer:tc( ?MODULE, loop, [Fh, Hash, 3]), T = lists:sum(A), P = [ N / T * 100 || N <- A ], {{elapsed_time, MS / 1000000}, {result, A}, {total, T}, {perc, P}}. loop(Fh, Hash, Count) -> case file:read_line(Fh) of eof -> [ wat:get(N) || N <- lists:seq(0,Count-1) ]; {error, Error} -> io:format("error:~p~n", [Error]); {ok, Line} -> N = erlang:Hash(Line) rem Count, wat:add(N, 1), loop(Fh, Hash, Count) end.
Running csum/scum on a MacBook Pro with 2 cores and SMP enabled:
4> csum:start(crc32,"test.txt"). {{elapsed_time,0.668354}, {result,[49001,48963,48743]}, {total,146707}, {perc,[33.40058756569216,33.37468559782423, 33.224726836483605]}} 5> scum:start(crc32,"test.txt"). {{elapsed_time,0.642855}, {result,[49001,48963,48743]}, {total,146707}, {perc,[33.40058756569216,33.37468559782423, 33.224726836483605]}}
Using "+A 10":
5> csum:start(crc32,"test.txt"). {{elapsed_time,3.597195}, {result,[49001,48963,48743]}, {total,146707}, {perc,[33.40058756569216,33.37468559782423, 33.224726836483605]}} 6> scum:start(crc32,"test.txt"). {{elapsed_time,2.839503}, {result,[49001,48963,48743]}, {total,146707}, {perc,[33.40058756569216,33.37468559782423, 33.224726836483605]}}