Skip to content

Julep: More support for working with immutables #11902

@Keno

Description

@Keno

This Julep is motivated by the current difficulties of working with immutables, particularly tuples. This issue aims to capture the result of the JuliaCon discussions between @JeffBezanson @carnaval @vtjnash @yuyichao and myself.

Working with tuples as fixed size arrays is currently quite cumbersome, particularly because they are hard to construct (since they can't be changed after constructing). To address

setindex! on a Ref

Ref creates a mutable container around an immutable object. This allows us to create changed immutables by putting them inside a Ref, modifying them in place and then pulling the changed value out. To support this, we can defined setindex! on Ref, giving it an index chain to modify, e.g.

ref = Ref{Tuple{Tuple{Int32,Int64},Int64}}(((1,2),3))
ref[1,1] = 4
@assert ref == ((4,2),3)

On tuples, this should generally be lowered to an appropriate getlementptr and store (assuming the tuples are on the stack) or an appropriate insertelement. This would allow construction of long tuples as follows:

ref = Ref{NTuple{1000,Int64}}()
for i = 1:1000
    ref[i] = i
end
return ref[] # This is now our constructed tuple

Complications with general immutables

This syntax should eventually also extend to generic immutables, but that need not be part of the initial implementation:

immutable foo
y::Int64
end
immutable bar
x::foo
end
ref = Ref{bar}()
ref[:x,:y] = 4
ref[] # bar(foo(4))

However, semantically, we do not want to allow setting arbitrary fields in immutables, because those immutables may then no longer obey invariants imposed by the constructor. To properly support this use case, we propose lowering the above ref[:x,:y] = 4 as (semantically at least)

ref[] = setindex(ref[],:x,setindex(ref[:x],:y,4))

where setindex is a new generic function that creates a copy of the passed in first argument but modifying the identified field to the given new value. To support this in general, a default version of setindex would be created by default unless an inner constructor is specified (i.e. the same way in which default constructors are currently created). People needing to enforce invariants on their immutables would then be expected to provide a method of setindex (perhaps defining it within the type block to get access to new), that checks that the appropriate invariants are maintained. Additionally, setindex would support a field index as a second argument, as well as providing a definition that takes keyword arguments and semantically applies setindex several times to change all arguments.

Metadata

Metadata

Assignees

Labels

julepJulia Enhancement Proposal

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions