在Julia中,如何正确地对调用方提供的(超级)类型的参数执行方法分派?

在Julia中,如何正确地对调用方提供的(超级)类型的参数执行方法分派?,julia,Julia,我想定义一个函数f(x,t::Type),根据isa(x,t)是否执行不同的行为。假设我想调用b1(x),如果是,则调用b2(x) 我知道我可以在运行时执行如下动态检查: function f(x, t::Type) if isa(x, t) b1(x) else b2(x) end end 然而,有没有一种方法可以完全通过参数化方法分派来实现这一点?例如,如果我定义 f{T}(x::T, t::Type{T}) = b1(x) f(x, t::Type) = b2

我想定义一个函数
f(x,t::Type)
,根据
isa(x,t)
是否执行不同的行为。假设我想调用
b1(x)
,如果是,则调用
b2(x)

我知道我可以在运行时执行如下动态检查:

function f(x, t::Type)
  if isa(x, t)
    b1(x)
  else
    b2(x)
  end
end
然而,有没有一种方法可以完全通过参数化方法分派来实现这一点?例如,如果我定义

f{T}(x::T, t::Type{T}) = b1(x)
f(x, t::Type) = b2(x)
对于
f(1,Int)
f(1.0,Int)
调用正确的行为。但我希望这也适用于
t
的所有子类型:

f(1, Number)
这实际上调用了
b2
,因为
f
的第一个签名不匹配。有趣的是,
f(x::Number,t::Type{Number})=b1(x)
在这种情况下会匹配

我是不是漏掉了什么明显的东西

这显然是一个bug,在0.4中已修复


问题:

  • 为什么
    f{T}(x::T,T::Type{T})
    f(1,Number)
    不匹配,即使
    T
    Number
    )有一个匹配的类型替换


  • 使用
    f{T2,T1回答您的问题:

  • 正如user3580870所评论的,这在Julia0.4中似乎是可行的
  • 这是“三角分派”,尚未实施。请参阅
  • 取决于。编译器可以在编译时计算
    isa(x,t)
    ,并消除分支。但是,使用
    isa
    仍有一些可能的方法不太理想:
    • 如果两个分支返回不同的类型,则类型推断将无法正确推断返回类型,因为它发生在
      isa(x,t)
      变成常量之前。(这可能代价高昂;下面其他可能的去优化可能不是什么大问题。)
    • 如果一个分支执行堆分配,而另一个不执行,则可能会发出不必要的GC帧
    • 该函数不能内联
  • 内部函数将与使用
    isa
    等类似的性能问题。从Julia 0.5开始,在这种情况下,内部函数应该与顶级函数一样高效
  • 归档一个bug;-)。我认为这应该是可行的。在0.4中修复的任何东西都可能被后端口到0.3。但是如果失败,
    isa
    不是一个好方法,只要它不会导致类型推断问题

  • 我有版本0.4.0-dev+1307和f(1,编号)您说得对,我已经确认这在0.4.0-dev+1521上有效。感谢您快速而出色的回答。这在0.4中确实有效,解决了我的问题。但是您能否详细说明内部函数方法的性能问题,或者指导我到一个可以了解更多信息的地方?为什么这比在顶层定义函数?只是澄清一下:如果调用的函数确实返回不同类型的对象,
    f{T}(x::T,T::Type{T})=b1(x)
    -方法会更快?