-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Julep: setfield! for mutable references to immutables #17115
Comments
#11902 ? |
yep, just more general. could generalize to arrays if we folded get/setfield and arrayref/set |
Yes, this is #11902 + extra syntax. Do note the discussion on constraints currently enforced by immutable constructors though. |
Of course since that was posted, I've pretty much come around that there is a distinct difference between regular immutables and those that enforce extra constraints (e.g. Rational). I think it would be fine to allow this in general and have a separate syntax ( |
For the purpose of atomic operation, I was thinking about generalizing the |
Note also that unlike #11902, this doesn't use |
Nice. |
That's exactly why I was thinking about using a E.g. |
I like this idea, but would like to note that it makes immutables behave
semantically different than mutables, not just being more restricted as
they are right now. Example: assign the same immutable to two fields, then
modify it through one of them.
|
Would immutables bound to non-const local variables be eligible for
mutation as well?
|
@toivoh Probably not according to this question and Jeff's answer below it. |
Well, I would say that Jeffs answer (quoted from #5333)
applies equally the whole idea of this Julep, not just the case of immutables stored in local variables? |
To get rid of the subtly different behavior depending on the runtime type of
This could be parsed into
etc. where
where It's not so easy to find an appealing syntax for this though, which is lightweight, makes it clear what happens, and is available. Another thing that the example highlights is that the proposal so far is a bit like adding |
I like this idea a lot! Couldn't immutables call their constructor whenever they are copied to the stack (i.e. directly assigned to a variable, as an immutable)? One simple way would be to have the user define a constructor from the "`Pos` stores a positive number"
immutable Pos{T}
val::T
Pos(x) = x >= 0 ? new(x) : error("must be positive")
Pos(r::RefValue{Pos{T}}) = r[].val >= 0 ? new(r[].val) : error("must be positive")
end There would be a default, costless constructor. If the user defines any constructor, and they want to enable copying from the heap (where someone might have used a pointer to mutate the values) then they would need to have explicitly defined such a constructor. That way it is free in the usual case, and invariants are still defined when the variable is a "direct" immutable (or a field of an immutable, etc). Users could add an extra "unsafe" constuctor, for efficiency in certain circumstances. Trying to worry about if it follows invariants on the heap seems utterly hopeless, but e.g. whenever |
I think that Jeff's comment still applies. Even if we restrict ourselves to the cases when The effect is very similar to the one that Jeff talks about in the comment: in some cases the mutation will be visible in another variable that was eg previously initialized as |
@toivoh: I think your point is fairly subtle (I'm having trouble following it) and would be clearer if you can spell out a case where the difference in behavior is externally visible. |
I think the point is that v = x.y
x.y.z = t May or may not mutate |
Right. Another equivalent case is:
|
We can only call
setfield!
on a mutable, so calling it on a immutable has been an error. This makes it hard to efficiently construct immutable objects incrementally. To fix, we propose making it possible to havesetfield!
modify fields inside of immutable objects that are wrapped in mutable objects. As will be shown later, this wouldn't alter existing semantics. This proposal also is an implementation of the concept that the object nursery is editable and then the object should be come immutable when done constructing it.To support this proposal, the
setfield!
function will get a multi-arg form, with the following behaviors:setfield!(x, a, b, c, value)
mutates the right most mutable object to change the value of its fields to be equivalent to copying the immutable objects and updating the referenced field.Then in the front-end, we will lower the syntax form
x.a.b.c = value
to the multi-argsetfield!
(instead of the current lowering that mixessetfield!
andgetfield
). In the mutable case, this will not change any behavior since it still assigns to the right-most field. In the immutable case, it would now be possible to assign through a mutable object, resulting in a transparent/fused copy/assignment that maintains the semantics of both the update of a mutable field with a new copy, and the fixedness of the immutable value. This lowering change has precedent, since it would be semantically similar to the way thatsetindex!
is handled. Oscar tells me that Inference already has the logic to ensure this lowers efficiently to avoid allocating extra values, and codegen will also be able to handle this efficiently.tl;dr The syntax:
would now be valid, as long as at least one of the referenced fields is mutable.
(opened at the insistence of @carnaval, to summarize recent discussions)
The text was updated successfully, but these errors were encountered: