0

I'm trying to create a typespec that represents a fixed length framed binary packet. Therefore using a bitstring of fixed N bytes (say 25 for example) seemed like the right idea.

The Elixir typespec docs stated the following:

                                ## Bitstrings
| <<>>                          # empty bitstring
| <<_::size>>                   # size is 0 or a positive integer
| <<_::_*unit>>                 # unit is an integer from 1 to 256
| <<_::size, _::_*unit>>

From this I would assume you could use @spec my_type :: <_::25, _::_*8>>

@type my_type :: <<_::25, _::_*8>>

@spec my_type_test() :: my_type
def my_type_test() do
    # 25 byte bitstring with start-of-frame byte
    << 0xA5::size(8) , 0::size(24)-unit(8) >>
end

But Dialyzer comes back with the following:

[ElixirLS Dialyzer] Invalid type specification for function 
'TestModule':my_type_test/0. The success typing 
is () -> <<_:200>>

Huh? But they're both bitstrings and the bit length is the same!

Anybody know why Dialyzer doesn't like this?

1 Answers1

1

The number just after :: specifies the number of bits, not bytes. If you want the type to match 25 bytes plus N * 8 bytes, the type needs to be:

@type my_type :: <<_::200, _::_*64>>

After this change, your original expression passes Dialyzer's checks and incrementing the size by 1 bit or 1 byte fails, as expected.

Dogbert
  • 212,659
  • 41
  • 396
  • 397
  • thanks, i misunderstood that spec. I changed it to <<_::200>> . Out of curiosity i also tried <<_::(25*8)>> but Dialyzer said " type '*'(_,_) undefined ". also didn't work for an annotation like @my_bitsize 200 . Do you know why those don't work either? – Matthew Di Nardo Jun 06 '18 at 21:00