Hi,
I just came across some nice pattern, while working on GLUtils.
I don’t know if it’s already commonly known as its pretty simple, but I’m 
pretty excited, as it is the first step in the direction of writing fast 
code for unknown types.
(Which is quite huge, for re-usability of code)
Problem it solves:
You have a calculation on some type, whereas the type can be anything, but 
needs to satisfy certain properties.
So you can write some specialized functions without checks, for types, 
where you already know that they satisfy the properties, and you write a 
function
which takes Any as a type, and does the calculation after it did some 
checks, which sacrifices performance.
You can leave out the checks, to let the runtime check if the type 
satisfies the properties, but that doesn’t always work (for example, if you 
interface with C, where you just get segfaults, if something is wrong)
and you sacrifice meaningful error messages.
So why not use multiple dispatch and eval, to make specialized functions 
for new types, that satisfy the properties?
Example from my GLUtil package, which extracts eltypes from any immutable 
vector, or color type (could be extended to matrixes):


function eltype(x::Any)
    T = typeof(x)
        # type checks
    if !isbits(T)
        error(T, " is not a bitstype, so it doesn't have the right memory 
layout")
    end
    types = T.types

    if isempty(types)
        error(T, " does not have any fields")
    end

    ftype = first(types)
    if any(t -> t!= ftype, types)
        error("field types are not homogenious for: ", T)
    end
    # We can return the field type, 
    # this means we can make a more specific function for this type
    eval(( :(fieldtype(x::$T) = $ftype) ))
    return ftype
end

Another one, which probably would need some more work :


function plus(a, b)
    T = typeof(a)
    @assert T == typeof(b) # don't neccessarily need to be of the same type, 
but which type to return if not the same?
    types = T.types

    # type checks
    if isempty(types)
        error(T, " does not have any fields")
    end
    if !all(t -> t <: Number, types)
        error("Not all field types are a number for: ", T)
    end

    fields = names(T)

    # create args for creating the resulting addition
    args = ntuple(i -> begin
        :(a.$(fields[i]) + b.$(fields[i]))
    end, length(fields))

    body = quote # creating the new type
        $T($(args...))
    end
    println("I needed to do all the tests :(")
    # create new specialized function
    f = eval( :(plus(a::$T, b::$T) = $body) )
    return f(a,b)
end
immutable TEST
    x::Float32
    y::Float32
end
t1 = TEST1(3,2)
@show plus(t1, t1) --> I needed to do all the tests :( \n TEST(6f0,4f0)
@show plus(t1, t1) --> TEST(6f0,4f0)

​

Reply via email to