Skip to content

Dispatch based on compile-time function evaluation #8154

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
timholy opened this issue Aug 27, 2014 · 8 comments
Closed

Dispatch based on compile-time function evaluation #8154

timholy opened this issue Aug 27, 2014 · 8 comments
Labels
speculative Whether the change will be implemented is speculative

Comments

@timholy
Copy link
Member

timholy commented Aug 27, 2014

Once staged functions land, my next wish-list item 😄 will likely be the ability to dispatch based on a boolean-valued function:

getpixelintensity(img::has_time_axis(img), i::Real, j::Real) =
    timeslice(img, i, j)  # a slice, containing a vector of values
getpixelintensity(img::AbstractArray, i::Real, j::Real) = img[i,j]  # scalar

stagedfunction has_time_axis(A::NamedAxesArray)
    ret = any(n -> n == :time, axesnames(A))
    :($ret)
end

This kind of dispatch is difficult to express with conventional mechanisms, because img might have any of the following types:

NamedAxesArray{T, 2, (:y, :x)}
NamedAxesArray{T, 3, (:x, :y, :time)}
NamedAxesArray{T, 3, (:time, :x, :y)}
NamedAxesArray{T, 4, (:color, :y, :x, :time)}

etc. Of course one can use non-dispatch based mechanisms, but those incur runtime overhead and might not be type-stable.

Ideally, the function after :: could accept more than just the argument itself. has_n_spatial_dimensions(img, 2), etc.

Any thoughts about whether this is worth the effort? I should emphasize that this is highly speculative, and I am concerned about suggesting big changes to Julia for a use case that may yet crumble 😉. So we should make sure there are other applications for this idea, too.

@ivarne
Copy link
Member

ivarne commented Aug 27, 2014

Could the same problem be solved by a dynamic Union type?

eg

function has_time_axis(A::NamedAxesArray)
    any(n -> n == :time, axesnames(A))
end
const Has_time_axis = DynamicUnion(has_time_axis)

An extendible Union type, might also be a building block for interfaces, where the is_in_union function can test if certain methods are implemented on a type. Anyway this will greatly complicate dispatch for functions that has one method that uses this crazy functionality.

@rfourquet
Copy link
Member

I find getpixelintensity(img::has_time_axis(img), i::Real, j::Real) very confusing: IIUC, img is an array, but has_time_axis(img) is a Bool, not even a type? Maybe getpixelintensity(img::(has_time_axis(img) ? NamedAxesArray : None), i::Real, j::Real) (this looks a lot like enable_if and SFINAE from C++).
Would the following dispatching be inlined eventually? (gpi for getpixelintensity):

type Value{B} end
gpi(img::AbstractArray, i::Real, j::Real) = gpi(img, i, j, Value{has_time_axis(img)})
gpi(img, i, j, ::Type{Value{true}}) = timeslice(img, i, j)
gpi(img, i, j, ::Type{Value{false}}) = img[i,j]

Remember also the constructor trick:

type gpi{B} 
    if B
        gpi(img, i, j) = timeslice(img, i, j)
    else
        gpi(img, i, j) = img[i, j]
    end
end
gpi(img::AbstractArray, i::Real, j::Real) = gpi{has_time_axis(img)}(img, i, j)

@rfourquet
Copy link
Member

BTW, it seems that staged functions can be emulated in this case, unfortunately this is not inlined apparently:

type has_time_axis{A}
    ret = any(n -> n == :time, axesnames(A))
    has_time_axis() = ret
end
has_time_axis{A<:NamedAxesArray}(::A) = has_time_axis{A}()

@timholy
Copy link
Member Author

timholy commented Aug 27, 2014

@rfourquet, one way to make this less confusing is to view the current x::T as being equivalent to x::isa(x, T).

@timholy
Copy link
Member Author

timholy commented Aug 27, 2014

You are right, though that if I modified the stagedfunction to return

immutable TypeConstant{C} end
stagedfunction has_time_axis(A::NamedAxesArray)
    ret = any(n -> n == :time, axesnames(A))
    retc = TypeConstant{ret}
    :($retc)
end

then I could dispatch on it. Not as pretty a syntax, however 😄.

@JeffBezanson
Copy link
Member

I don't think a special feature is needed for this. Being able to dispatch on Type{true} vs Type{false} is sufficient, and if you're willing to use TypeConstant{C} then it works today.

@timholy
Copy link
Member Author

timholy commented Aug 27, 2014

Yep, that's reasonable.

@timholy
Copy link
Member Author

timholy commented Sep 5, 2014

Over in #2345 (comment), I point out that this basically gives us multiple inheritance (it's traits-based rather than type-based).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
speculative Whether the change will be implemented is speculative
Projects
None yet
Development

No branches or pull requests

4 participants