DataStructures.jl icon indicating copy to clipboard operation
DataStructures.jl copied to clipboard

Set Empty DefaultDict to new struct object may leads to pass by copy

Open dmoliveira opened this issue 2 years ago • 1 comments

Based on my tests using the DataStructures package, if you create a new DefaultDict empty and pass it to your new object it does not pass by reference but by copy and this leads to strange behaviour (imho). This is very subtle for me and should give some error or warning when you try.

SIMULATE THE ISSUE

1. Create Empty DefaultDict

julia> using DataStructures

julia> a = DefaultDict(0)
DefaultDict{Any, Any, Int64}()

2. Create your struct as dict

julia> struct D1
       data::Dict
       end

3. Assign the default dict to your object

julia> d = D1(a)
D1(Dict{Any, Any}())

4. Update initial default dict

julia> a["A"] = 1
1

5. Check the object and you will see that it was not updated as expected

julia> d.data
Dict{Any, Any}()

HOW TO AVOID THIS BEHAVIOUR

Basically in the data struct instead of using a Dict object use AbstractDict and the issue will not happen. But I think for me this creates some inconsistency in the code. What we should do?

julia> using DataStructures

julia> a = DefaultDict(0)
DefaultDict{Any, Any, Int64}()

julia> struct D2
       data::AbstractDict
       end

julia> d = D2(a)
D2(DefaultDict{Any, Any, Int64}())

julia> a["A"] = 1
1

julia> d.data
DefaultDict{Any, Any, Int64} with 1 entry:
  "A" => 1

dmoliveira avatar Mar 20 '22 03:03 dmoliveira

The following is a quote from the manual: (https://docs.julialang.org/en/v1/manual/conversion-and-promotion/#When-is-convert-called?)

convert(T, x) is expected to return the original x if x is already of type T. In contrast, if T is a mutable collection type then T(x) should always make a new collection (copying elements from x).

So I think the behavior you have observed is expected.

StephenVavasis avatar Mar 21 '22 01:03 StephenVavasis