From d8f6033090d1f242a33e42d20c67cc918246e548 Mon Sep 17 00:00:00 2001 From: Alex Arslan Date: Tue, 23 Jan 2018 13:25:45 -0800 Subject: [PATCH 1/2] Change keyword arguments to regular NamedTuples Revert "undo breaking change to kwargs iteration order" (#25290) This reverts commit b90274e3a575519a46d7b87312a8d47f81ec3f1c. --- base/errorshow.jl | 10 +++++----- base/interactiveutil.jl | 2 +- base/methodshow.jl | 2 +- src/julia-syntax.scm | 15 +++++++-------- stdlib/DelimitedFiles/src/DelimitedFiles.jl | 4 ++-- stdlib/Distributed/src/cluster.jl | 2 +- test/deprecation_exec.jl | 2 +- test/errorshow.jl | 8 ++++---- test/keywordargs.jl | 6 +++--- test/syntax.jl | 2 +- 10 files changed, 26 insertions(+), 27 deletions(-) diff --git a/base/errorshow.jl b/base/errorshow.jl index de9f53fffb37f..8b360c1fdefa6 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -164,13 +164,13 @@ function showerror(io::IO, ex::MethodError) ft = typeof(f) name = ft.name.mt.name f_is_function = false - kwargs = () + kwargs = NamedTuple() if startswith(string(ft.name.name), "#kw#") f = ex.args[2] ft = typeof(f) name = ft.name.mt.name arg_types_param = arg_types_param[3:end] - kwargs = pairs(ex.args[1]) + kwargs = ex.args[1] ex = MethodError(f, ex.args[3:end]) end if f == Base.convert && length(arg_types_param) == 2 && !is_arg_types @@ -214,7 +214,7 @@ function showerror(io::IO, ex::MethodError) end if !isempty(kwargs) print(io, "; ") - for (i, (k, v)) in enumerate(kwargs) + for (i, (k, v)) in enumerate(pairs(kwargs)) print(io, k, "=") show(IOContext(io, :limit => true), v) i == length(kwargs) || print(io, ", ") @@ -294,7 +294,7 @@ function showerror_nostdio(err, msg::AbstractString) ccall(:jl_printf, Cint, (Ptr{Cvoid},Cstring), stderr_stream, "\n") end -function show_method_candidates(io::IO, ex::MethodError, @nospecialize kwargs=()) +function show_method_candidates(io::IO, ex::MethodError, kwargs::NamedTuple = NamedTuple()) is_arg_types = isa(ex.args, DataType) arg_types = is_arg_types ? ex.args : typesof(ex.args...) arg_types_param = Any[arg_types.parameters...] @@ -425,7 +425,7 @@ function show_method_candidates(io::IO, ex::MethodError, @nospecialize kwargs=() if !isempty(kwargs) unexpected = Symbol[] if isempty(kwords) || !(any(endswith(string(kword), "...") for kword in kwords)) - for (k, v) in kwargs + for (k, v) in pairs(kwargs) if !(k in kwords) push!(unexpected, k) end diff --git a/base/interactiveutil.jl b/base/interactiveutil.jl index fc25bc0c7b019..2d3cc1163f56d 100644 --- a/base/interactiveutil.jl +++ b/base/interactiveutil.jl @@ -420,7 +420,7 @@ function gen_call_with_extracted_types(__module__, fcn, ex0) return quote local arg1 = $(esc(args[1])) $(fcn)(Core.kwfunc(arg1), - Tuple{Any, Core.Typeof(arg1), + Tuple{NamedTuple, Core.Typeof(arg1), $(typesof)($(map(esc, args[2:end])...)).parameters...}) end elseif ex0.head == :call diff --git a/base/methodshow.jl b/base/methodshow.jl index 379670383ff61..3a7ee5bbdc9fd 100644 --- a/base/methodshow.jl +++ b/base/methodshow.jl @@ -75,7 +75,7 @@ function arg_decl_parts(m::Method) end function kwarg_decl(m::Method, kwtype::DataType) - sig = rewrap_unionall(Tuple{kwtype, Any, unwrap_unionall(m.sig).parameters...}, m.sig) + sig = rewrap_unionall(Tuple{kwtype, NamedTuple, unwrap_unionall(m.sig).parameters...}, m.sig) kwli = ccall(:jl_methtable_lookup, Any, (Any, Any, UInt), kwtype.name.mt, sig, typemax(UInt)) if kwli !== nothing kwli = kwli::Method diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 8b23fdcd1d331..a07078e61fd68 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -478,7 +478,7 @@ ,(let (;; call mangled(vals..., [rest_kw,] pargs..., [vararg]...) (ret `(return (call ,mangled ,@(if ordered-defaults keynames vals) - ,@(if (null? restkw) '() `((call (top pairs) (call (core NamedTuple))))) + ,@(if (null? restkw) '() `((call (core NamedTuple)))) ,@(map arg-name pargl) ,@(if (null? vararg) '() (list `(... ,(arg-name (car vararg))))))))) @@ -513,13 +513,13 @@ `((|::| ;; if there are optional positional args, we need to be able to reference the function name ,(if (any kwarg? pargl) (gensy) UNUSED) - (call (core kwftype) ,ftype)) ,kw ,@pargl ,@vararg) + (call (core kwftype) ,ftype)) (:: ,kw (core NamedTuple)) ,@pargl ,@vararg) `(block ,(scopenest keynames (map (lambda (v dflt) (let* ((k (decl-var v)) - (rval0 `(call (top getindex) ,kw (inert ,k))) + (rval0 `(call (top getfield) ,kw (quote ,k))) ;; note: if the "declared" type of a KW arg includes something ;; from keyword-sparams then don't assert it here, since those ;; static parameters don't have values yet. instead, the type @@ -548,11 +548,10 @@ ,dflt))) vars vals) `(block - (= ,rkw (call (top pairs) - ,(if (null? keynames) - kw - `(call (top structdiff) ,kw (curly (core NamedTuple) - (tuple ,@(map quotify keynames))))))) + (= ,rkw ,(if (null? keynames) + kw + `(call (top structdiff) ,kw (curly (core NamedTuple) + (tuple ,@(map quotify keynames)))))) ,@(if (null? restkw) `((if (call (top isempty) ,rkw) (null) diff --git a/stdlib/DelimitedFiles/src/DelimitedFiles.jl b/stdlib/DelimitedFiles/src/DelimitedFiles.jl index 5b17981cb4222..f5dbcdd07f78f 100644 --- a/stdlib/DelimitedFiles/src/DelimitedFiles.jl +++ b/stdlib/DelimitedFiles/src/DelimitedFiles.jl @@ -483,8 +483,8 @@ const valid_opts = [:header, :has_header, :use_mmap, :quotes, :comments, :dims, const valid_opt_types = [Bool, Bool, Bool, Bool, Bool, NTuple{2,Integer}, Char, Integer, Bool] function val_opts(opts) - d = Dict{Symbol, Union{Bool, NTuple{2, Integer}, Char, Integer}}() - for (opt_name, opt_val) in opts + d = Dict{Symbol,Union{Bool,NTuple{2,Integer},Char,Integer}}() + for (opt_name, opt_val) in pairs(opts) in(opt_name, valid_opts) || throw(ArgumentError("unknown option $opt_name")) opt_typ = valid_opt_types[findfirst(equalto(opt_name), valid_opts)::Int] diff --git a/stdlib/Distributed/src/cluster.jl b/stdlib/Distributed/src/cluster.jl index 9864a26dd5b4b..35a74d31ff891 100644 --- a/stdlib/Distributed/src/cluster.jl +++ b/stdlib/Distributed/src/cluster.jl @@ -370,7 +370,7 @@ function addprocs(manager::ClusterManager; kwargs...) end function addprocs_locked(manager::ClusterManager; kwargs...) - params = merge(default_addprocs_params(), AnyDict(kwargs)) + params = merge(default_addprocs_params(), AnyDict(pairs(kwargs))) topology(Symbol(params[:topology])) if PGRP.topology != :all_to_all diff --git a/test/deprecation_exec.jl b/test/deprecation_exec.jl index 9cf9846aa398e..3f90a79557788 100644 --- a/test/deprecation_exec.jl +++ b/test/deprecation_exec.jl @@ -103,7 +103,7 @@ f25130() testlogs = testlogger.logs @test length(testlogs) == 2 @test testlogs[1].id != testlogs[2].id -@test testlogs[1].kwargs[:caller].func == Symbol("top-level scope") +@test testlogs[1].kwargs.caller.func == Symbol("top-level scope") @test all(l.message == "f25130 message" for l in testlogs) global_logger(prev_logger) diff --git a/test/errorshow.jl b/test/errorshow.jl index 440c9c902a27c..29b3ffd8d6685 100644 --- a/test/errorshow.jl +++ b/test/errorshow.jl @@ -116,11 +116,11 @@ error_out3 = String(take!(buf)) c7line = @__LINE__() + 1 method_c7(a, b; kargs...) = a -Base.show_method_candidates(buf, MethodError(method_c7, (1, 1)), pairs((x = 1, y = 2))) +Base.show_method_candidates(buf, MethodError(method_c7, (1, 1)), (x = 1, y = 2)) @test String(take!(buf)) == "\nClosest candidates are:\n method_c7(::Any, ::Any; kargs...)$cfile$c7line" c8line = @__LINE__() + 1 method_c8(a, b; y=1, w=1) = a -Base.show_method_candidates(buf, MethodError(method_c8, (1, 1)), pairs((x = 1, y = 2, z = 1, w = 1))) +Base.show_method_candidates(buf, MethodError(method_c8, (1, 1)), (x = 1, y = 2, z = 1, w = 1)) @test String(take!(buf)) == "\nClosest candidates are:\n method_c8(::Any, ::Any; y, w)$cfile$c8line got unsupported keyword arguments \"x\", \"z\"" let no_kwsorter_match, e @@ -134,7 +134,7 @@ ac15639line = @__LINE__ addConstraint_15639(c::Int32) = c addConstraint_15639(c::Int64; uncset=nothing) = addConstraint_15639(Int32(c), uncset=uncset) -Base.show_method_candidates(buf, MethodError(addConstraint_15639, (Int32(1),)), pairs((uncset = nothing,))) +Base.show_method_candidates(buf, MethodError(addConstraint_15639, (Int32(1),)), (uncset = nothing,)) @test String(take!(buf)) == "\nClosest candidates are:\n addConstraint_15639(::Int32)$cfile$(ac15639line + 1) got unsupported keyword argument \"uncset\"\n addConstraint_15639(!Matched::Int64; uncset)$cfile$(ac15639line + 2)" macro except_str(expr, err_type) @@ -487,7 +487,7 @@ foo_9965(x::Int) = 2x end @test typeof(ex) == MethodError io = IOBuffer() - Base.show_method_candidates(io, ex, pairs((w = true,))) + Base.show_method_candidates(io, ex, (w = true,)) @test contains(String(take!(io)), "got unsupported keyword argument \"w\"") end diff --git a/test/keywordargs.jl b/test/keywordargs.jl index 47ffc65e4d0dd..36887303b5e64 100644 --- a/test/keywordargs.jl +++ b/test/keywordargs.jl @@ -188,7 +188,7 @@ function test4974(;kwargs...) end end -@test test4974(a=1) == (2, pairs((a=1,))) +@test test4974(a=1) == (2, (a=1,)) @testset "issue #7704, computed keywords" begin @test kwf1(1; :tens => 2) == 21 @@ -300,11 +300,11 @@ end counter += 1 return counter end - f(args...; kws...) = (args, values(kws)) + f(args...; kws...) = (args, kws) @test f(get_next(), a=get_next(), get_next(), b=get_next(), get_next(), [get_next(), get_next()]...; c=get_next(), (d = get_next(), f = get_next())...) == - ((1, 3, 5, 6, 7), + ((1,3,5,6,7), (a = 2, b = 4, c = 8, d = 9, f = 10)) end diff --git a/test/syntax.jl b/test/syntax.jl index 2e5e3c3ab43ca..5aa0418d7f9bb 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -839,7 +839,7 @@ let f = function (x; kw...) g = function (x; a = 2) return (x, a) end - @test f(1) == (1, pairs(NamedTuple())) + @test f(1) == (1, NamedTuple()) @test g(1) == (1, 2) end From 09e9ec6be0e9d72966abf53c39eddf964cd82d65 Mon Sep 17 00:00:00 2001 From: Alex Arslan Date: Tue, 23 Jan 2018 13:46:28 -0800 Subject: [PATCH 2/2] Add NEWS entry for kwargs as NamedTuples --- NEWS.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/NEWS.md b/NEWS.md index 3db283a9a3b2c..cc49bae9d65d9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -196,6 +196,11 @@ Breaking changes This section lists changes that do not have deprecation warnings. + * Keyword arguments are now `NamedTuple`s. This is a breaking change because iterating + `NamedTuple`s produces values only, whereas previously iteration over keyword arguments + inside of functions produced name, value pairs. The `pairs` function can be used to + extract both names and values. ([#24795]) + * `readuntil` now does *not* include the delimiter in its result, matching the behavior of `readline`. Pass `keep=true` to get the old behavior ([#25633]). @@ -1221,6 +1226,7 @@ Command-line option changes [#24785]: https://github.com/JuliaLang/julia/issues/24785 [#24786]: https://github.com/JuliaLang/julia/issues/24786 [#24794]: https://github.com/JuliaLang/julia/issues/24794 +[#24795]: https://github.com/JuliaLang/julia/issues/24795 [#24805]: https://github.com/JuliaLang/julia/issues/24805 [#24808]: https://github.com/JuliaLang/julia/issues/24808 [#24831]: https://github.com/JuliaLang/julia/issues/24831