diff --git a/base/array.jl b/base/array.jl index 34e0c052546b9..de9341cbd1e0c 100644 --- a/base/array.jl +++ b/base/array.jl @@ -834,6 +834,41 @@ function setindex!(A::Array{T}, X::Array{T}, c::Colon) where T return A end +""" + setindex(collection, value, key...) + +Create a new collection with the element/elements of the location specified by `key` +replaced with `value`(s). + +# Implementation + +`setindex(collection, value, key...)` must have the property such that + +```julia +y1 = setindex(x, value, key...) + +y2 = copy′(x) +@assert convert.(eltype(y2), x) == y2 + +y2[key...] = value +@assert convert.(eltype(y2), y1) == y2 +``` + +with a suitable definition of `copy′` such that `y2[key...] = value` succeeds. + +`setindex` should support more combinations of arguments by widening collection +type as required. +""" +function setindex end + +function setindex(xs::AbstractArray, v, I...) + T = promote_type(eltype(xs), typeof(v)) + ys = similar(xs, T) + copy!(ys, xs) + ys[I...] = v + return ys +end + # efficiently grow an array _growbeg!(a::Vector, delta::Integer) = diff --git a/base/dict.jl b/base/dict.jl index 8c1d762527bb8..60e0d08e07706 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -391,6 +391,15 @@ function setindex!(h::Dict{K,V}, v0, key::K) where V where K return h end +function setindex(d0::Dict, v, k) + K = promote_type(keytype(d0), typeof(k)) + V = promote_type(valtype(d0), typeof(v)) + d = Dict{K, V}() + copy!(d, d0) + d[k] = v + return d +end + """ get!(collection, key, default) diff --git a/test/arrayops.jl b/test/arrayops.jl index 4f4f9c53b865b..d969a3d4e0db2 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -2651,6 +2651,20 @@ end # Throws ArgumentError for negative dimensions in Array @test_throws ArgumentError fill('a', -10) +@testset "setindex" begin + ==ₜ(_, _) = false + ==ₜ(x::T, y::T) where T = x == y + + @test @inferred(Base.setindex(Int[1, 2], 3.0, 2)) ==ₜ [1.0, 3.0] + @test @inferred(Base.setindex(Int[1, 2, 3], :two, 2)) ==ₜ [1, :two, 3] + + @testset "no mutation" begin + arr = [1] + @test Base.setindex(arr, 2, 1) ==ₜ [2] + @test arr == [1] + end +end + @testset "Issue 33919" begin A = Array[rand(2, 3), rand(3, 1)] B = Array[rand(2, 2), rand(1, 4)] diff --git a/test/dict.jl b/test/dict.jl index 1224d41bb220a..dbf36a6c4498b 100644 --- a/test/dict.jl +++ b/test/dict.jl @@ -1072,3 +1072,21 @@ end @test testdict[:b] == 1 end end + +@testset "setindex" begin + ==ₜ(_, _) = false + ==ₜ(x::T, y::T) where T = x == y + + @test @inferred(Base.setindex(Dict(:a=>1, :b=>2), 10, :a)) ==ₜ + Dict(:a=>10, :b=>2) + @test @inferred(Base.setindex(Dict(:a=>1, :b=>2), 3, "c")) ==ₜ + Dict(:a=>1, :b=>2, "c"=>3) + @test @inferred(Base.setindex(Dict(:a=>1, :b=>2), 3.0, :c)) ==ₜ + Dict(:a=>1.0, :b=>2.0, :c=>3.0) + + @testset "no mutation" begin + dict = Dict(:a=>1, :b=>2) + @test Base.setindex(dict, 10, :a) ==ₜ Dict(:a=>10, :b=>2) + @test dict == Dict(:a=>1, :b=>2) + end +end