In implementing new kinds of numbers, I've found it difficult to know just 
how many functions I need to implement for the general library to "just 
work" on them. Take as an example a byte-swapped, e.g. big-endian, integer. 
This is handy when doing memory-mapped I/O on a file with data written in 
network order. It would be nice to just implement, say, Int32BigEndian and 
have it act like a real number. (Then I could just reinterpret a mmaped 
array and work directly off it) In general, we'd convert to Int32 at the 
earliest opportunity we had. For instance the following macro introduces a 
new type which claims to be derived from $base_type, and implements 
conversions and promotion rules to get it into a native form ($n_type) 
whenever it's used.

macro encoded_bitstype(name, base_type, bits_type, n_type, to_n, from_n)
    quote
        immutable $name <: $base_type
            bits::$bits_type
        end

        Base.bits(x::$name) = bits(x.bits)
        Base.bswap(x::$name) = $name(bswap(x.bits))

        Base.convert(::Type{$n_type}, x::$name) = $to_n(x.bits)
        Base.convert(::Type{$name}, x::$n_type) = $name($from_n(x))
        Base.promote_rule(::Type{$name}, ::Type{$n_type}) = $n_type
        Base.promote_rule(::Type{$name}, ::Type{$base_type}) = $n_type
    end
end

I can use it like this

@encoded_bitstype(Int32BigEndian, Signed, Int32, Int32, bswap, bswap)

But unfortunately, it doesn't work out of the box because the conversions 
need to be explicit. I noticed that many of the math functions promote 
their arguments to a common type, but the following trick doesn't work, 
presumably because the promotion algorithm doesn't ask to promote types 
that are already identical.

        Base.promote_rule(::Type{$name}, ::Type{$name}) = $n_type

It seems like there are a couple of issues this raises, and I know I've 
seen similar questions on this list as people implement new kinds of 
things, e.g. exotic matrices.

1. One possibility would be to allow an implicit promotion, perhaps 
expressed as the self-promotion above. I say I'm a Int32BigEndian, or 
CompressedVector, or what have you, and provide a way to turn me into an 
Int32 or Vector implicitly to take advantage of all the functions already 
written on those types. I'm not sure this is a great option for the 
language since it's been explicitly avoided elsewhere. but I'm curious if 
there have been any discussions in this direction

2. If instead I want to say "this new type acts like an Integer", there's 
no canonical place for me to find out what all the functions are I need to 
implement. Ultimately, these are like Haskell's typeclasses, Ord, Eq, etc. 
By trial and error, we can determine many of them and implement them this 
way

macro as_number(name, n_type)
     quote
        global +(x::$name, y::$name) = +(convert($n_type, x), 
convert($n_type, y))
        global *(x::$name, y::$name) = *(convert($n_type, x), 
convert($n_type, y))
        global -(x::$name, y::$name) = -(convert($n_type, x), 
convert($n_type, y))
        global -(x::$name) = -convert($n_type, x)
        global /(x::$name, y::$name) = /(convert($n_type, x), 
convert($n_type, y))
        global ^(x::$name, y::$name) = ^(convert($n_type, x), 
convert($n_type, y))
        global ==(x::$name, y::$name) = (==)(convert($n_type, x), 
convert($n_type, y))
        global < (x::$name, y::$name) = (< )(convert($n_type, x), 
convert($n_type, y)) 
        Base.flipsign(x::$name, y::$name) = Base.flipsign(convert($n_type, 
x), convert($n_type, y))
    end
end

But I don't know if I've found them all, and my guesses may well change as 
implementation details inside the base library change. Gradual typing is 
great, but with such a powerful base library already in place, it would be 
good to have a facility to know which functions are associated with which 
named behaviors.

Since we already have abstract classes in place, e.g. Signed, Number, etc., 
it would be natural to extract a list of functions which operate on them, 
or, even better, allow the type declarer to specify which functions 
*should* operate on that abstract class, typeclass or interface style?

Are there any recommendations in place, or updates to the language planned, 
to address these sorts of topics?





Reply via email to