Inconsistent namespacing for maps? - erlang

I think namespacing of maps (at least in R19) is pretty weird. Consider the example:
14> M = #{a => 2, b => 3, c => 4}.
#{a => 2,b => 3,c => 4}
15> M.
#{a => 2,b => 3,c => 4}
16> map_size(M).
3
17> maps:map_size(M).
** exception error: undefined function maps:map_size/1
18> to_list(M).
** exception error: undefined shell command to_list/1
19> maps:to_list(M).
[{a,2},{b,3},{c,4}]
So, map_size is available in default namespace but not in maps:. However, to_list/1 exhibits opposite behavior. I haven't tried other functions, but even these results are surprising.
Am I missing some important undercurrent here or is this just an example of carelessness in language design?

I see some logic to this. The map_size/1 function is also available as maps:size/1, where both names contain the information you need: it takes a map, and returns the size. On the other hand, the name to_list doesn't say what you're converting from. There are several to_list functions in the default namespace already:
atom_to_list
binary_to_list
float_to_list
integer_to_list
pid_to_list
tuple_to_list
So the inconsistency here is that while "size" is available as map_size/1 and maps:size/1, the function map_to_list is missing. As Dogbert notes in the comments, this is presumably because map_size is available in guard tests, and thus deserves a special place. (I seem to remember that there are functions in other modules that are available in guard tests, but my memory might be deceiving me.)

Related

Which way to compare maps in Elixir

Given two large and different maps defined as follows
Interactive Elixir (1.9.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> m1 = Map.new(1..1_000_000 |> Enum.map(&{&1, &1})); :ok
:ok
iex(2)> m2 = Map.new(2..1_000_000 |> Enum.map(&{&1, &1})); :ok
:ok
it takes a significant time difference when comparing them using ==/2 and Map.equal?/2
iex(3)> :timer.tc(fn -> m1 == m2 end)
{21, false}
iex(4)> :timer.tc(fn -> Map.equal?(m1, m2) end)
{20487, false}
What is the reason of this time difference between ==/2 and Map.equal?/2, and which to use?
Equivalently, which to use between ==/2 and ===/2? (because Map.equal?/2 calls to ===/2, see here)
Thanks
Indeed, Map.equal?/2 is simply delegating to Kernel.===/2.
Kernel.===/2 is delegating to :erlang."=:="/2 and Kernel.==/2 is delegating to :erlang."=="/2. The latter compares numbers while the former compares values and types.
Consider the following example.
%{1 => 1} == %{1 => 1.0}
#⇒ true
%{1 => 1} === %{1 => 1.0}
#⇒ false
That said, Kernel.===/2 should compare all the values. OTOH, Erlang/OTP reference explicitly states that
Maps are ordered by size, two maps with the same size are compared by keys in ascending term order and then by values in key order. In maps, key order integers types are considered less than floats types.
If it was indeed true, two maps of the different size, as in your example, should have returned in the nearly same time.
The summing up, I would consider this time difference to be a bug in :erlang."=:="/2 implementation, worth to report to Erlang team.

Eunit assertions error reporting the wrong module

I started writing some functions to help test assertions on maps.
Let's say I have the following map:
#{a => 0, b => 2}
And after calling a function in my business logic I expect the map to look like this:
#{a => 1, b => 2}
In other words, I expect
the map to have the same number of keys after the update
the value of a to change from 0 to 1
the value of b unchanged
I could just leave this test to pattern matching, however, if I have a large map with a lot of keys (and perhaps even a lot of submaps) it is not obvious where the problem might be - at least it takes some time to find the problem (maybe some values which I expected to be updated were not - or maybe there are some extra keys, etc, etc - I hope you get the point).
So as a start, I came up with the following helper function in my module:
-module(asserts).
-include_lib("eunit/include/eunit.hrl").
maps_assert_map_has_updated_values(BaseMap, Updates, ResultingMap) ->
BaseMapKeys = lists:sort(maps:keys(BaseMap)),
ResultingMapKeys = lists:sort(maps:keys(ResultingMap)),
UpdatesKeys = lists:sort(maps:keys(Updates)),
BaseMapWithoutUpdates = maps:without(UpdatesKeys, BaseMap),
BaseMapKeysWithoutUpdates = lists:sort(maps:keys(BaseMapWithoutUpdates)),
ResultingMapWithoutUpdates = maps:without(UpdatesKeys, ResultingMap),
[
?_assertEqual(BaseMapKeys, ResultingMapKeys),
lists:foldl(
fun(Key, Acc) -> [?_assertEqual({Key, maps:get(Key, Updates)},
{Key, maps:get(Key, ResultingMap)}) | Acc] end,
[],
UpdatesKeys
),
lists:foldl(
fun(Key, Acc) -> [?_assertEqual({Key, true},
{Key, maps:is_key(Key, ResultingMap)}) | Acc] end,
[],
UpdatesKeys
),
lists:foldl(
fun(Key, Acc) -> [?_assertEqual({Key, maps:get(Key, BaseMapWithoutUpdates)},
{Key, maps:get(Key, ResultingMapWithoutUpdates)}) | Acc] end,
[],
BaseMapKeysWithoutUpdates
)
].
I call this from another module, which is executed by eunit:
-module(map_tests).
-include_lib("eunit/include/eunit.hrl").
simple_map_test_() ->
asserts:maps_assert_map_has_updated_values(
#{a => 0, b => 2},
#{a => 1},
#{a => 1, b => 3}).
And I get the following error message:
asserts:30: maps_assert_map_has_updated_values...*failed* in function asserts:'-maps_assert_map_has_updated_values/3-fun-8-'/3 (test/asserts.erl, line 31)
**error:{assertEqual_failed,[{module,asserts},
{line,31},
{expression,"{ Key , maps : get ( Key , ResultingMapWithoutUpdates ) }"},
{expected,{b,2}},
{value,{b,3}}]}
Which is almost what I want in that it reports the problematic key and the problematic values in the map, however it reports the error being in the asserts module, even though I am interested in seeing the actual test that failed, not the reference to the assertions module. I thought test generators were good for exactly that, but I wasn't able to get this working in that way.
Is there any way in which I can make eunit report the actual test module (map_tests, function/test simple_map_test line X) instead of my asserts module?
The problem is, the ?_assert... macros are compiled into the asserts module, and that's where EUnit does its magic to figure out modules and line numbers (at compile time, that is). If you replace the maps_assert_map_has_updated_values function with a macro that you put in an header file that you include, you should see the right stack trace.

conversion data with erlang

my question now is :
I have the variavle M which contains : 37.5 (as you see is integer)
I want to convert M in order to be string "37.5"
so 37.5 should became "37.5"
I try with function :
M2=integer_to_list(M)
but when I execute this function it displays this error :
** exception error: bad argument
in function integer_to_list/1
called as integer_to_list(37.5)
integer_to_list wont work in that situation because 37.5 is a float and not an integer. Erlang does have float_to_list, but the output is usually pretty unusable.
Instead, I would recommend looking into mochiweb project for pretty conversion of floats to lists. In particular, the mochinum module:
> M = 37.5,
> mochinum:digits(M).
"37.5"
#chops has a great answer, IMO (using mochinum:digits/1), but you might also get something out of looking at the io_lib module. For example:
8> io_lib:format("~.2f",[37.5]).
["37.50"]
9> io_lib:format("~.1f",[37.5]).
["37.5"]
I realize this might not be exactly what you are looking for, and in this case I think looking at/using the mochinum module is an efficient way to go, but io_lib is often overlooked and provides a really useful set of functions for formatting lists / strings

How to get the name of a function?

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]).

What does array * string mean in Ruby?

I was looking through some Rails source code and came across
# File vendor/rails/activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb, line 129
129: def target!
130: #target * ''
131: end
What does the * '' do? Is that multiplication by an empty string...? And why would you do that.
This is a bizarre syntax. These are equivalent:
>> [1, 2, 3] * 'joiner'
=> "1joiner2joiner3"
>> [1, 2, 3].join 'joiner'
=> "1joiner2joiner3"
so in this case it joins all the entries of #target into one string, with nothing between the entries.
Note: if you do something like [1, 2, 3] * 3 (using an int instead of a str), you'll get three concatenated copies of the array instead.
It does the same thing as:
["foo","bar","baz"].join
http://ruby-doc.org/core/classes/Array.html#M002210
Per Z.E.D.'s suggestion, you would use it if you want to confuse people and make your code more error prone.
Really cryptic code indeed.
After checking the source code, I realized that #target is actually an Array instance, I know you can do stuff like this
[5] * 5 # => [5,5,5,5,5]
I don't know where Array#* is defined (maybe in ActiveSupport), but what I can tell you is that, this is the behaviour when it gets multiplied by a String
[1,2,3] * 'comma' # => "1comma2comma3"
[1,2,3] * '' # => '123'
So I can infer it is concatanating all the elements of the array without any separators.
Array#* with a String argument is equivalent to Array#join.
Two comments:
Having a ! end a method name implies that it's a mutating operation, which this example doesn't seem to be.
As others have stated it's indeed cryptic. I would go for #target.to_s or #target.join
The only reason I'd see someone wanting to use * to join an array of strings is if they want to avoid the word join, which is also used on threads.
With the following:
strings = ["John", "Smith"]
threads = [Thread.new{puts "hai"}, Thread.new{ puts "world!"}]
strings.join(" ") # Legit
threads.each {|thread| thread.join} # Legit
you could make the mistake of doing
threads.join # Not legit, but won't raise an error
If you replaced strings.join with strings.*, then you'd have fewer joins in your code. Now you could do a grep for them, and check that each one is being done to a thread, not to an array. In fact, you could choose to make Array#join throw an exception.

Resources