10
votes

I am currently trying to understand how binary-size(number) works in Elixir. In the example from The Little Elixir & OTP Guidebook there is a section where they break apart a 128 byte ID3 tag. The tag has the following properties:

  • 3 byte header
  • 30 byte title tag
  • 30 byte artist tag
  • 30 byte album tag
  • 4 byte year tag
  • Rest is packing

The way in which they extract this in the book is

<< "TAG", title :: binary-size(30), artist :: binary-size(30), album :: binary-size(30), year:: binary-size(4), _ :: binary >>

I am having trouble understanding how each value gets the correct value from binary-size(#num). Maybe it is the order in which the pattern matching is taking place and I am having trouble understand that. Currently I am approaching it as we first pattern match the header which is three bytes since it is hardcoded as "TAG", at this point I'm not sure how we can get the value of 30 bytes from binary-size(30). Is this operation being split up into two separate parts? Are we saying that first from 128, total byte size, we subtract 30 and then assign the value of size(30) to the title, and then carry this updated size to each value in the binary pattern match propagating any changes along the way?

1

1 Answers

22
votes

I think you may be getting confused with how Elixir does it's pattern matching and the syntax it uses.

Firstly I know it isn't really seen anywhere else in syntax but it's binary-size(30) not binary - size(30).

So basically, it's saying that the size of the binary is 30 (e.g. 30 bytes) not binary subtract 30 bytes.

So for example:

iex(1)> string = "binary matching string"
"binary matching string"
iex(2)> <<head::binary-size(1), _rest::binary>> = string
"binary matching string"
iex(3)> head
"b"

So here we are saying match the value of head to the first byte of the string "binary matching string" which means that head is b.

We then assign _rest to match the rest of the binary regardless of size.

We aren't limited to strictly matching bytes however. Since << >> is called a bitstring in elixir, if we leave off binary and just do size, the number passed in is measured in bits so therefore val::binary-size(1) is the same as val::size(8) (well sort of see below).

iex(4)> <<head::size(8), _rest::binary>> = string
"binary matching string"
iex(5)> head
98
iex(6)> <<head>>
"b"

To really understand it better, I would definitely recommend opening up an IEX session and typing h <<>> and reading through that.