julialang:能否(应该)在编译时捕获此类型错误?

julialang: can (should) this type error be caught at compile time?

function somefun()
    x::Int = 1
    x = 0.5
end

编译时没有警告。当然调用它会产生 InexactError: Int64(0.5)。问题:你能强制执行编译时检查吗?

从这个意义上说,Julia 是一种动态语言。所以,不,如果没有先 运行 函数,您似乎无法检测到赋值的结果是否会导致这样的错误,因为这种类型检查是在运行时完成的。

我自己也不确定,所以我将这个函数包装在一个模块中,以在 运行 函数不存在的情况下强制(预)编译,结果是没有抛出任何错误,这证实了这个想法。 (如果您想了解我的意思,请参阅 )。

说到这里,回答您问题的精神:有没有办法避免这种模糊的运行时错误以意想不到的方式出现?

是的。考虑以下两个几乎等效的函数:

function fun1(x     ); y::Int = x; return y; end;
function fun2(x::Int); y::Int = x; return y; end;

fun1(0.5)   # ERROR: InexactError: Int64(0.5)
fun2(0.5)   # ERROR: MethodError: no method matching fun2(::Float64)

你可能会想,大不了,我们把一个错误换成了另一个错误。但这种情况并非如此。首先,您不知道您的输入会导致问题,直到它在函数中被使用为止。而在第二种情况下,您在 调用 函数时有效地执行了类型检查。

这是一个简单的编程示例 "by contract",通过使用 Julia 优雅的 type-checking 系统。有关详细信息,请参阅 Design By Contract

所以你的问题的答案是,是的,如果你重新考虑你的设计并遵循良好的编程实践,以便尽早发现这种错误,那么你可以避免它们在以后出现的模糊场景中发生它们很难修复或检测。

Julia 手册提供了一个 style guide 也可能有帮助(我上面给出的例子就在顶部!)。

值得思考 "compile time" 在 Julia 中的真正含义 — 因为它可能不是您所想的。

定义函数时:

julia> function somefun()
           x::Int = 1
           x = 0.5
       end
somefun (generic function with 1 method)

没有编译它。事实上,在您调用它之前,Julia 不会编译它。 Julia 的编译器可以被认为是 Just-Barely-Ahead-Of-Time,与典型的 JIT 或 AOT 设计形成对比。

现在,当您调用该函数时,它会对其进行编译,然后运行会抛出错误。您可以在第一次调用该函数时看到这种编译发生——它需要更多的时间和内存,因为它会生成和缓存专用代码:

julia> @time try somefun() catch end
  0.005828 seconds (6.76 k allocations: 400.791 KiB)

julia> @time try somefun() catch end
  0.000107 seconds (6 allocations: 208 bytes)

因此,也许您可​​以看到,使用 Julia 的编译模型,它是否在编译时被捕获并不重要——即使 Julia 拒绝编译(和缓存)代码,它的行为也会完全一样你目前看到的。它仍然允许您首先 定义 函数,并且它仍然只会在调用函数时抛出错误。

你想问的问题是 Julia 是否可以(或应该)在函数 定义 时捕捉到这个错误。然后真正的问题是 - 定义一个总是导致错误的方法是否可以? a function like error itself 呢?在 Julia 中,定义一个像这样无条件出错的方法是完全可以的,而且这样做是有充分理由的。

现在,有一些方法可以询问 Julia 是否能够检测到此方法总是无条件出错:

julia> @code_typed somefun()
CodeInfo(
1 ─     invoke Base.convert(Main.Int::Type{Int64}, 0.5::Float64)::Union{}
└──     $(Expr(:unreachable))::Union{}
) => Union{}

这是 Julia 编译过程的第一步,在这种情况下,它可以看到 convert(Int, 0.5) 之外的所有内容都是 unreachable——也就是说,它会出错。此外,它知道由于函数永远不会 return,它的 return 类型是 Union{}(也就是说,不可能 returned 类型!)所以你可以要求 Julia 使用 @inferred 宏作为测试套件的一部分来执行此步骤。