Type piracy?


#1

I have the following function that takes a tuple and converts it to an unsigned integer:

function f(::Type{UInt16}, x::NTuple{2, UInt8})
    x1 = 0x0001 * x[1]
    x2 = 0x0100 * x[2]
    x1 + x2
end

What would be the right name for f? It used to be Base.convert, but I think that fits the definition of type piracy, Base.reinterpret probably too. I named it to_unsigned for now and removed the first argument.


#2

Can’t you encode your x::NTuple{2, UInt8} in your own type:

struct TwoUInt8
x1::UInt8
x2::UInt8
end

and then define the appropriate Base.convert method? That avoids type piracy.


#3

that is not really an option here, because I have tuples of various lengths and want to make UInts from them. Haven’t thought about declaring my own type though, I could simply declare const NBytes{N} = NTuple{N, UInt8} where N.


#4

That wouldn’t solve the type piracy, that’s just an alias


#5

If you’re using a type alias, it’s still type piracy if you’re extending a function from Base.

I kind of like mauro3's idea. Why is having tuples of various lengths a problem? You could just parameterize the type on N.

Just a wild thought: what you’re doing is kind of like Base.read, so you could do something like

struct StaticByteStream{N}
    tup::NTuple{N, UInt8}
end

Base.read(s::StaticByteStream{2}, ::Type{UInt16}) = ...

#6

Another option would be to just call your function combine.


#7

I was just toying around with this and found the following weird performance issue (Julia Version 0.7.0-DEV.4570):

function f(::Type{UInt16}, x::NTuple{2, UInt8})
    x1 = 0x0001 * x[1]
    x2 = 0x0100 * x[2]
    x1 + x2
end

const NBytes{N} = NTuple{N, UInt8}
function f(::Type{UInt16}, x::NBytes{2})
    x1 = 0x0001 * x[1]
    x2 = 0x0100 * x[2]
    x1 + x2
end

julia> @btime f(UInt16, (0x01, 0x02))
  0.017 ns (0 allocations: 0 bytes)
0x0201

julia> x = NBytes((0x01, 0x02))
(0x01, 0x02)

julia> @btime f(UInt16, $x)
  1.690 ns (0 allocations: 0 bytes)
0x0201

`reinterpret` to a single value from an array of a smaller data type
#8

Seeing that there is no one best solution I will probably give it a separate name.


#9

The “fast” one isn’t doing anything. The compiler can see the input and just optimized everything out.


#10

I tried several versions of this function and it is pretty impressive what the compiler can optimize out in Julia 0.7 compared to 0.6.

Why does reinterpret not work on tuples, for me this would seem like the most obvious choice for something like this?


#11

Is there a zero overhead way to do this the other way round? the best I could come up with is the following:

function to_byte_tuple(x::T) where T <: Unsigned
    ntuple(i -> (x >>  (8 * (i - 1))) % UInt8, sizeof(T))
end