maps string question

9 views
Skip to first unread message

Java House

unread,
Oct 13, 2021, 5:05:54 PM10/13/21
to erlang-q...@erlang.org
Hello
I am having a problem with maps and strings as keys.
My understanding that the the two string formats "string" and <<"string">> are identical but as you can see from the transcript bellow maps does not think so.
I searched but I couldn't find any function to convert form "string" to <<"string">> or the other way around.
How can I make maps to accept both format of strings?

Erlang/OTP 24 [erts-12.0] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit]

Eshell V12.0  (abort with ^G)
1> Key1 = "key1".
"key1"
2>
2> Key11 = <<"key1">>.
<<"key1">>
3>
3> string:equal(Key1, Key11).
true
4>
4> Map = maps:new().
#{}
5>
5> Map1 = maps:put("key1", {something}, Map).
#{"key1" => {something}}
6>
6> maps:get(Key1, Map1).
{something}
7>
7> maps:get(Key11, Map1).
** exception error: bad key: <<"key1">>
     in function  maps:get/2
        called as maps:get(<<"key1">>,#{"key1" => {something}})
        *** argument 2: not a map
8>
8> maps:get("key1", Map1).
{something}
9>
9> maps:get(<<"key1">>, Map1).
** exception error: bad key: <<"key1">>
     in function  maps:get/2
        called as maps:get(<<"key1">>,#{"key1" => {something}})
        *** argument 2: not a map
10> 

Roberto Ostinelli

unread,
Oct 13, 2021, 5:24:37 PM10/13/21
to Java House, erlang-q...@erlang.org
<<“key”>> is a binary, “key” is a list, so they are not the same. maps:get/2 raises because the key is not found.

> string:equal(Key1, Key11).

The string representation for both is the same, hence this return true.

Hope this helps,
r.

> On 13 Oct 2021, at 23:05, Java House <java...@gmail.com> wrote:
>
> 

Hugo Mills

unread,
Oct 13, 2021, 5:25:07 PM10/13/21
to Java House, erlang-q...@erlang.org
On Wed, Oct 13, 2021 at 11:05:33PM +0200, Java House wrote:
> Hello
> I am having a problem with maps and strings as keys.
> My understanding that the the two string formats "string" and <<"string">>
> are identical but as you can see from the transcript bellow maps does not
> think so.

No, they're not identical.

"foo" is a list of integers, one per code-point in the string.
<<"foo">> is a binary, which is a packed sequence of bytes. There's a
third form for strings, the iolist, which is a (possibly deeply)
nested list of lists and/or binaries. This is what you often get back
from the functions in the string module, for example.

The two (three) forms are not equal, even if representing the same
conceptual string, so "foo" and <<"foo">> will compare differently.

> I searched but I couldn't find any function to convert form "string" to
> <<"string">> or the other way around.

erlang:list_to_binary/1 and erlang:binary_to_list/1,3 would do the
job if your strings are purely ASCII (i.e. code-points of 127 or
less). Otherwise, unicode:characters_to_binary/1,2,3 and
unicode:characters_to_list/1,2 are probably the place to look. The
unicode functions and the list_to_binary function will also accept
iolists.

> How can I make maps to accept both format of strings?

They'll acccept both... but they'll look like different keys. You
can't make the list do an automatic conversion. You need to decide on
which of the two forms you're going to use (I recommend binaries), and
ensure that every access converts to binary before using a map
accessor. You may want to write some helper functions for this.

Hugo.
--
Hugo Mills | You can play with your friends' privates, but you
hugo@... carfax.org.uk | can't play with your friends' childrens' privates.
http://carfax.org.uk/ |
PGP: E2AB1DE4 | C++ coding rule

Anthony Howe

unread,
Oct 13, 2021, 5:27:15 PM10/13/21
to erlang-q...@erlang.org
On 2021-10-13 17:05, Java House wrote:
> Hello
> I am having a problem with maps and strings as keys.
> My understanding that the the two string formats "string" and <<"string">>
> are identical but as you can see from the transcript bellow maps does not

They are identical in content, but not in structure / type.

Using a list-string as a key will be different from using a binary-string. You
will need to convert depending which key type you use. Using a mix of
list-string and binary-string type as map keys will probably yield confusing
results.

As I understand binary-strings (more like C-string) are better than list-strings
and I would key on binary-string normally.

> Eshell V12.0 (abort with ^G)
> 1> Key1 = "key1".
> "key1"
> 2>
> 2> Key11 = <<"key1">>.
> <<"key1">>
> 3>
> 3> string:equal(Key1, Key11).
> true
> 4>
> 4> Map = maps:new().
> #{}
> 5>
> 5> Map1 = maps:put("key1", {something}, Map).
> #{"key1" => {something}}
> 6>
> 6> maps:get(Key1, Map1).
> {something}
> 7>
> 7> maps:get(Key11, Map1).

Try

maps:get(binary_to_list(Key11), Map1).

> ** exception error: bad key: <<"key1">>
> in function maps:get/2
> called as maps:get(<<"key1">>,#{"key1" => {something}})
> *** argument 2: not a map
> 8>
> 8> maps:get("key1", Map1).
> {something}
> 9>
> 9> maps:get(<<"key1">>, Map1).
> ** exception error: bad key: <<"key1">>
> in function maps:get/2
> called as maps:get(<<"key1">>,#{"key1" => {something}})
> *** argument 2: not a map
> 10>
>


--
Anthony C Howe SnertSoft
ach...@snert.com Twitter: SirWumpus BarricadeMX & Milters
http://snert.com/ http://nanozen.snert.com/ http://snertsoft.com/

Java House

unread,
Oct 13, 2021, 6:19:28 PM10/13/21
to Roberto Ostinelli, erlang-q...@erlang.org
Thank you Roberto and Mark for the clarification.
I am loading the data from a file using the file:consult(MapData)
Currently the file looks like this
{"key1", {"data1"}}.
{"key2", {"data2"}}.

If I want to have all binary for consistency does this means that I need to write into the file as
{<<"key1">>, {<<"data1">>}}.
{<<"key2">>, {<<"data2">>}}.

Kind Regards
Nikolas

Maria Scott

unread,
Oct 16, 2021, 12:15:27 PM10/16/21
to Java House, erlang-q...@erlang.org
Hi Nikolas,

> I am loading the data from a file using the file:consult(MapData)
> Currently the file looks like this
> {"key1", {"data1"}}.
> {"key2", {"data2"}}.
>
> If I want to have all binary for consistency does this means that I need to write into the file as
> {<<"key1">>, {<<"data1">>}}.
> {<<"key2">>, {<<"data2">>}}.

Maybe you should tell us a bit more about what you are trying to do here, in context =^^=

It doesn't really matter whether you are using lists or binaries here, as long as you are using the same to access them in the program.
And however that may be, as the original question was about keys, there is no need to change the values to binaries here, as long as your program handles either lists or binaries or both.

If, by a guess, you are using this file as some sort of config from which you are filling a virgin map, you could just write a map into the file, like #{<<"key1">> => {<<"value1">>}, <<"key2">> => {<<"value2">>}}.

Anyway... no offense, but I get the impression that you don't really know/understand what lists and binaries are? "..." and <<"...">> are not different ways to say string-ish. There are no strings in Erlang. "key1" is just convenient syntactic sugar to write a list of integers, namely [107, 101, 121, 49], and <<"key1">> is just convenient syntactic sugar to write a binary, namely <<107, 101, 121, 49>>.
For an easy-to-graps explanation, you may want to read https://learnyousomeerlang.com/starting-out-for-real#lists and the following paragraphs.

Kind regards,
Maria

Java House

unread,
Oct 17, 2021, 1:43:34 PM10/17/21
to Maria Scott, erlang-q...@erlang.org
Thank you Maria, for the explanation.
I have indeed only the last year start concentrating my efforts in Erlang. 
I am trying to build a prototype for one of my ideas using Erlang as I want to try something different than Java.
It is easy to forget each time the special handling of strings in erlang.
I have checked several erlang projects in github and my understanding is that most projects are converting to binary all strings just before adding them into structures like maps.
It is really sad that at least BIF  when reading files are not automatically converting all double quoted data  to binary instead of lists.

Kind regards
Nikolas
Reply all
Reply to author
Forward
0 new messages