如何将函数标记为 `@deprecate`(弃用)?

9
我正试图理解Julia版本1.5中的@deprecate宏的工作方式。不幸的是,文档对我来说并不清楚:
“@deprecate old new [ex=true]”
使旧方法过期并指定替换调用的新方法。通过将ex设置为false,防止@deprecate导出old。@deprecate定义了一个与old具有相同签名的新方法。
警告: 从Julia 1.5开始,由@deprecate定义的函数在未设置--depwarn=yes标志的情况下运行julia时不会打印警告,因为--depwarn选项的默认值为no。警告是从Pkg.test()运行的测试中打印出来的。
示例: julia> @deprecate old(x) new(x) old (generic function with 1 method) julia> @deprecate old(x) new(x) false false old (generic function with 1 method)
那么我该怎么办?
function old(x::Int)
    print("Old behavior")
end

function new(x::Int)
    print("New behavior")
end

# Adding true/false argument doesn't change my observations.
@deprecate old(x) new(x)  # false 


old(3)
# Prints "Old behaviour". No warning. 
# Also: The deprecation is not mentioned in the help (julia>? old)

这个@deprecate宏的目的似乎是替换函数?我认为这很反直觉。如何标记一个函数已被弃用(即用户应该收到警告,并获得提示以使用替代方案,同时还应在文档中说明)?
编辑:我注意到了我的错误。在这种情况下,签名(在我的情况下是::Int)必须完全相同才能起作用。但是,我如何获得警告?
1个回答

10
假设您的库在版本1中有以下公共API方法:
# v1.0.0
mult3(x::Int) = 3x

在版本2中,您希望停止支持mult3(这是一个重大变更)。但是,您仍然可以使用一种更通用的方法获得相同的功能:
# v2.0.0
mult(x, y) = x * y

版本1的用户习惯于使用mult3,这意味着当他们更新到v2时,他们的代码将会出错。因此,您可能希望在v1.x系列中发布一个中间版本,其中mult3已弃用并以mult为基础实现:

# v1.1 - transition

# This is the new API for v2
mult(x, y) = x*y

# The old API is still supported, but deprecated and implemented using the old one
@deprecate mult3(x::Int) mult(3, x)

# The above is more or less equivalent to defining
# function mult3(x::Int)
#    # print an error message is `--depwarn` has been set
#    return mult(3, x)
# end

v1.x版本中的v1 API并没有损坏,但是调用已过时方法的用户将看到以下类型的消息,以帮助他们过渡到更新的v2 API:

julia> mult3(14)
┌ Warning: `mult3(x::Int)` is deprecated, use `mult(3, x)` instead.
│   caller = top-level scope at REPL[3]:1
└ @ Core REPL[3]:1
42

(但从Julia 1.5开始,只有在Julia命令行中提供了--depwarn=yes或在Pkg.test()运行的测试套件中出现时,才会显示警告。)
(另外,正如在评论中提到的那样,您可能希望保留旧实现,当用户调用它时发出警告。为此,您可以直接使用Base.depwarn:)
# v1.1 - transition

# This is the new API for v2
mult(x, y) = x*y

# The old API is still supported, but deprecated
# It is implemented by itself:
function mult3(x)
    Base.depwarn("`mult3(x)` is deprecated, use `mult(3,x)` instead.", :mult3)
    return 3x
end

当在Julia的命令行中提供了--depwarn=yes选项时,这将产生与@deprecate相同类型的警告。
julia> mult3(14)
┌ Warning: `mult3(x)` is deprecated, use `mult(3,x)` instead.
│   caller = top-level scope at REPL[4]:1
└ @ Core REPL[4]:1
42

从 Julia 1.6 开始,depwarn 将接受一个关键字参数,用于强制发出警告,即使用户没有使用 --depwarn=yes 要求它们:

julia> Base.depwarn("Foo is deprecated", :foo, force=true)
┌ Warning: Foo is deprecated
│   caller = ip:0x0
└ @ Core :-1

2
谢谢你的回答。这解释了@deprecate背后的思想。我猜当每个人开始抱怨每个版本都重命名所有函数时,警告默认被禁用了。另一方面,我该如何实现我想要的功能?(不要替换该方法,甚至允许不指定替换,始终显示警告并包含在帮助文本中)。答案是这样的功能在标准库中不存在吗? - Adomas Baliuka
我不确定我理解你想要实现什么。如果你是指忽略--depwarn,那么我想@deprecate不是你想要的,而且我也不确定你能找到任何替代方案,它不会遵循这个特定命令行选项的含义。至于帮助文本,我想可以说@deprecate可以接受docstrings,以便可以对弃用函数进行文档记录。如果您想要,您可以提交问题报告。或者使用@doc手动记录已弃用的功能。 - François Févotte
2
@AdomasBaliuka,我认为你想问的是,如何保留旧的实现?您也可以将其保留在原地,并在方法体内使用Base.depwarn来引导用户使用替代方案。请参见https://github.com/JuliaImages/Images.jl/blob/de7d11fab7937efaa461874f2fa957dc0a31e602/src/deprecations.jl以获取一些示例。 - tholy
1
感谢@tholy,我编辑了我的答案以反映您的评论。 - François Févotte
2
值得注意的是,即将进入alpha阶段的Julia 1.6版本具有一个force关键字参数,它可以确保用户即使没有要求也能看到警告信息。 - tholy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接