Hi,
I’m kind new with elixir code and I was wondering if there away to create counter in it?
E,g,
x=0;
depf sum() {
x=x+1;
end
depf callsum() {
loop
sum();
}
Thanks,
SL
Hi,
I’m kind new with elixir code and I was wondering if there away to create counter in it?
E,g,
x=0;
depf sum() {
x=x+1;
end
depf callsum() {
loop
sum();
}
Thanks,
SL
In general there is nothing comparable to a “static variable” as you are used to it from C. This would violate the rules of immutability.
The concept that comes closest were a longrunning process which holds the counters value in its state.
But before explaining how to do that exactly, I’d like to ask what you need that counter for. Perhaps there are much more idiomatic ways to solve your particular problem than a stateholding process.
Thanks for your response.
Well, I’m trying to see how many atoms created in my apps.
I tried the erlang command, but I’m running OTA 19 and not 20. On 20 there’s build-in function for it.
So I thought to sum how many atom I have and print it.
How’d you know if you have created a new one or re-used an old one? There’s not really a way to check that in advance.
In OTP 19 though the following erlang code (shamelessly borrowed from https://engineering.klarna.com/monitoring-erlang-atoms-c1d6a741328e) can help to retrieve the currents atom table size:
-module(atom_table).
-export([count/0]).
count() ->
Info = erlang:system_info(info),
Chunks = binary:split(Info, <<"=">>, [global]),
[TabInfo] = [X || <<"index_table:atom_tab", X/binary>> <- Chunks],
Lines = binary:split(TabInfo, <<"\n">>, [global]),
Chunks2 = [binary:split(L, <<": ">>) || L <- Lines, L =/= <<>>],
binary_to_integer(proplists:get_value(<<"entries">>, Chunks2)).
It roughly translates to the following elixir code:
defmodule AtomTable do
@tab_prefix "index_table:atom_tab"
def count() do
data = :info
|> :erlang.system_info()
|> String.split("=")
|> Enum.filter(fn
@tab_prefix <> _ -> true
_ -> false
end)
|> hd()
|> rm_prefix()
|> String.split("\n")
|> Enum.reject(&String.empty?/1)
|> Enum.map(&String.split(&1, ": "))
"entries"
|> :proplist.get_value(data)
|> String.to_integer()
end
defp rm_prefix(@tab_prefix <> str), do: str
end
The translation is very rough and has its edges (also it is untested). Perhaps you just put the erlang module into src/atom_table.erl
in your project and call it as :atom_table.count()
.
I’n not sure if this trick still works in Erlang 20, but you can actually enumerate all the currently defined Atoms in Erlang 19.
A more verbose and pedestrian version:
## file: atom_info.ex
defmodule AtomInfo do
@info_begin <<"index_table:atom_tab">>
@info_end <<"=">>
@info_keys [:size, :limit, :entries]
@info_names Enum.reduce(@info_keys, %{}, &(Map.put &2, (Atom.to_string &1), &1))
def props do
all_info = :erlang.system_info :info
with {:ok, begin} <- (atom_info_begin all_info),
{:ok, length} <- (atom_info_length all_info, begin) do
# extract the atom_tab items from info
# and put the desired ones in a map
props =
all_info
|> Kernel.binary_part(begin, length)
|> Kernel.to_string()
|> String.split("\n", trim: true)
|> Enum.reduce(%{}, &put_props/2)
{:ok, props}
else
_ ->
{:error, :undefined}
end
end
defp atom_info_begin(info) do
case :binary.match info, @info_begin do
{start, length} ->
{:ok, start + length}
_ ->
{:error, :undefined}
end
end
defp atom_info_length(info, begin) do
remain = (Kernel.byte_size info) - begin
case :binary.match info, @info_end, [{:scope, {begin, remain}}] do
{end_pos, _length} ->
{:ok, end_pos - begin}
_ ->
{:ok, remain}
end
end
defp put_props(item, props) do
name_int_value = ~r/^([a-z]+)\s*:\s*(\d+)$/
with [_full, name, value] <- Regex.run(name_int_value, item),
{:ok, key} <- Map.fetch(@info_names, name) do
Map.put props, key, (String.to_integer value)
else
_->
props # i.e. don't add if match failed or name not listed
end
end
end
$ iex
iex(1)> c("atom_info.ex")
[AtomInfo]
iex(2)> AtomInfo.props
{:ok, %{entries: 13232, limit: 1048576, size: 13312}}
iex(3)>
Everyone so far is talking about counting atoms, but it seems to me that the more fundamental question here is about how to do iteration.
Iterating all existing atoms has been linked by @bbense, that that hasn’t been asked for…
The question was, how one could check how many atoms there are currently registered to avoid creating new ones when a certain threshold is reached,
Besides of what was asked or not asked… The easiest way to avoid overflowing the atom-table is to not create any new atoms, but those that are used literally in the sources…
thanks for you implementation its very helpful.