Skip to content

Commit

Permalink
required keyword arguments (#586)
Browse files Browse the repository at this point in the history
* required keyword arguments working

* using @test_throws and UndeKeywordError now

* defining UndefKeywordError only if not yet in Base

* corrected UndefKeywordError message

* added README entry for required keyword arguments

* Update README.md

* updated README with link
  • Loading branch information
timziebart authored and stevengj committed Jul 18, 2018
1 parent 3804559 commit a9b0a3d
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 0 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ Currently, the `@compat` macro supports the following syntaxes:
`foo(::CartesianRange{CartesianIndex{N}})` ([#20974]). Note that
`CartesianRange` now has two type parameters, so using them as
fields in other `struct`s requires manual intervention.

* Required keyword arguments ([#25830]). For example, `@compat foo(; x, y)` makes `x` and `y` required keyword arguments: when calling `foo`, an error is thrown if `x` or `y` is not explicitly provided.

## Module Aliases

Expand Down Expand Up @@ -633,6 +635,7 @@ includes this fix. Find the minimum version from there.
[#25780]: https://github.com/JuliaLang/julia/issues/25780
[#25812]: https://github.com/JuliaLang/julia/issues/25812
[#25819]: https://github.com/JuliaLang/julia/issues/25819
[#25830]: https://github.com/JuliaLang/julia/issues/25830
[#25873]: https://github.com/JuliaLang/julia/issues/25873
[#25896]: https://github.com/JuliaLang/julia/issues/25896
[#25935]: https://github.com/JuliaLang/julia/issues/25935
Expand Down
18 changes: 18 additions & 0 deletions src/compatmacro.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,31 @@ else
new_style_typealias(ex) = false
end

if !isdefined(Base, :UndefKeywordError)
struct UndefKeywordError <: Exception
kw
end
Base.showerror(io::IO, e::UndefKeywordError) = print(io, "UndefKeywordError: keyword argument $(e.kw) not assigned")
export UndefKeywordError
end

"Convert a functions symbol argument to the corresponding required keyword argument."
function symbol2kw(sym::Symbol)
Expr(:kw, sym, Expr(:call, throw, UndefKeywordError(sym)))
end
symbol2kw(arg) = arg

function _compat(ex::Expr)
if ex.head === :call
f = ex.args[1]
if VERSION < v"0.6.0-dev.826" && length(ex.args) == 3 && # julia#18510
istopsymbol(withincurly(ex.args[1]), :Base, :Nullable)
ex = Expr(:call, f, ex.args[2], Expr(:call, :(Compat._Nullable_field2), ex.args[3]))
end
if !isdefined(Base, :UndefKeywordError) && length(ex.args) > 1 && isexpr(ex.args[2], :parameters)
params = ex.args[2]
params.args = map(symbol2kw, params.args)
end
elseif ex.head === :curly
f = ex.args[1]
if VERSION < v"0.6.0-dev.2575" #20414
Expand Down
18 changes: 18 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1898,6 +1898,24 @@ let
@test Compat.split(str, r"\.+:\.+"; limit=3, keepempty=true) == ["a","ba","cba.:.:.dcba.:."]
end

let
# test required keyword arguments
@compat func1() = 1
@test func1() == 1 # using the function works
@compat func2(x) = x
@test func2(3) == 3 # using the function works
@compat func3(;y) = y
@test func3(y=2) == 2 # using the function works
@test_throws UndefKeywordError func3()
@compat func4(x; z) = x*z
@test func4(2,z=3) == 6 # using the function works
@test_throws UndefKeywordError func4(2)
@compat func5(;x=1, y) = x*y
@test func5(y=3) == 3
@test func5(y=3, x=2) == 6
@test_throws UndefKeywordError func5(x=2)
end

# 0.7.0-beta.73
let a = rand(5,5)
s = mapslices(sort, a, dims=[1])
Expand Down

0 comments on commit a9b0a3d

Please sign in to comment.