Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what's the difference between list_to_binary and iolist_to_binary?

Tags:

erlang

I only know list_to_binary in erlang otp, but today I see iolist_to_binary?

I tried it in erlang shell, but I can't find the difference.

(ppb1_bs6@esekilvxen263)59> list_to_binary([<<1>>, [1]]).
<<1,1>>
(ppb1_bs6@esekilvxen263)60> iolist_to_binary([<<1>>, [1]]).
<<1,1>>
(ppb1_bs6@esekilvxen263)61> iolist_to_binary([<<1>>, [1], 1999]).
** exception error: bad argument
     in function  iolist_to_binary/1
        called as iolist_to_binary([<<1>>,[1],1999])
(ppb1_bs6@esekilvxen263)62> list_to_binary([<<1>>, [1], 1999]).  
** exception error: bad argument
     in function  list_to_binary/1
        called as list_to_binary([<<1>>,[1],1999])
(ppb1_bs6@esekilvxen263)63> list_to_binary([<<1>>, [1], <<1999>>]).
<<1,1,207>>
(ppb1_bs6@esekilvxen263)64> ioslist_to_binary([<<1>>, [1], <<1999>>]).
** exception error: undefined shell command ioslist_to_binary/1
(ppb1_bs6@esekilvxen263)65> iolist_to_binary([<<1>>, [1], <<1999>>]). 
<<1,1,207>>

From the test, I think iolist_to_binary may be the same as list_to_binary.

like image 226
BlackMamba Avatar asked Nov 11 '15 06:11

BlackMamba


2 Answers

In current versions of Erlang/OTP both functions will automatically flatten the list or iolist() you provide, leaving functionally only one difference, which is that list_to_binary/1 will not accept a binary parameter, but iolist_to_binary/1 will:

1> erlang:iolist_to_binary(<<1,2,3>>). 
<<1,2,3>>

2> erlang:list_to_binary(<<1,2,3>>).  
** exception error: bad argument
     in function  list_to_binary/1
        called as list_to_binary(<<1,2,3>>)

This is clear from the type specification of iolist():

maybe_improper_list(byte() | binary() | iolist(), binary() | [])

As you can see, iolist() can be a binary, but clearly a list can never be a binary.

If you want to follow through the convolution of the improper list type you can find its definition, along with iolist() at (Erlang) Types and Function Specifications.

In terms of practical use iolist() is a messy or unflattened list. Think of it as a kind of lazy output, deliberately not flattened to be a proper list by the produver as an optimisation because not every consumer will need to flatten it. You can see what it looks like by checking the output of io_lib:format/2:

1> io_lib:format("Hello ~s ~b!~n", ["world", 834]).
    [72,101,108,108,111,32,"world",32,"834",33,"\n"]

Or:

2> io:format("~w~n", [  io_lib:format("Hello ~s ~b!~n", ["world", 834])  ]).
    [72,101,108,108,111,32,[119,111,114,108,100],32,[56,51,52],33,[10]]

I notice that many of your examples include the number 1999. Attempts to convert any list or iolist() which contain any number that is greater than 255 to a binary will always fail by the way:

8> erlang:list_to_binary([1,2,3,255]).  
<<1,2,3,255>>
9> erlang:list_to_binary([1,2,3,256]).
** exception error: bad argument
     in function  list_to_binary/1
        called as list_to_binary([1,2,3,256])

This is because it wants to create a list of bytes from your list, and a number above 255 is ambiguous in terms of its possible byte representation; it can't be known if you mean little endian or big endian, etc (see (Wikipedia) Endianness).

like image 86
Michael Avatar answered Sep 23 '22 05:09

Michael


The differences are not large. Type checking is done. But in the end caused by one and the same function. If I correctly found.

Source list_to_binary (https://github.com/erlang/otp/blob/maint/erts/emulator/beam/binary.c#L896):

BIF_RETTYPE list_to_binary_1(BIF_ALIST_1)
{
    return erts_list_to_binary_bif(BIF_P, BIF_ARG_1, bif_export[BIF_list_to_binary_1]);
}

Source iolist_to_binary (https://github.com/erlang/otp/blob/maint/erts/emulator/beam/binary.c#L903):

BIF_RETTYPE iolist_to_binary_1(BIF_ALIST_1)
{
    if (is_binary(BIF_ARG_1)) {
    BIF_RET(BIF_ARG_1);
    }
    return erts_list_to_binary_bif(BIF_P, BIF_ARG_1, bif_export[BIF_iolist_to_binary_1]);
}
like image 33
Dennis Y. Parygin Avatar answered Sep 21 '22 05:09

Dennis Y. Parygin