On Mon Feb 09 2015 at 7:59:20 PM <ele...@gmail.com> wrote:

>
>
> On Tuesday, February 10, 2015 at 1:25:15 AM UTC+11, Simon Danisch wrote:
>>
>> Someone else has to answer this. I suppose it's not that bad. The
>> immutables are getting copied into the heap allocated memory from the
>> array, which should be fairly okay to mutate?!
>> But I seriously don't know the details on this. From a semantic viewpoint
>> it's definitely not okay!
>>
>
> WARNING: if you use unsafe practices to mutate an immutable object you
> enter the realms of undefined behaviour where the compiler/runtime can do
> anything it likes from sending your details to Scammers-R-Us to eating your
> shorts.  Seriously if anything in the compiler optimisations, the runtime
> or garbage collector is changed to depend on immutables being, well,
> immutable, then it will cause unknown issues.  And there is no guarantee
> that this hasn't happened already, just your specific code hasn't hit it
> ... yet.
>
Semantically, modifying a field of the immutable in the array is the same
as reading the whole thing, creating a new immutable with one field
modified, and writing it back to the array. The only thing you are likely
missing by hacking unsafe_store in this manner is a missing TBAA
annotation. That's fairly unlikely to matter here though (more about this
below).

>
> Things that may be an issue include:
>
> 1. Julia now has a generational GC, does it assume immutable
> intergenerational pointers cannot change and doesn't rescan for them?
>
If your type contains pointers to other non-isbits types, you are probably
just as well off using a type. They are stored the same. Only `isbits`
types get the special inline-storage behavior.


>
> 2. Does the compiler generate the correct GC write barriers for unsafe
> operations and does it ignore immutables since they can't change?
>
No, it doesn't generate write barriers during calls to unsafe_store.
Although if you are writing bits data inside the immutable, it hardly
matters, since it doesn't need a write barrier to do that.


>
> 3. Do optimisations use copies of immutables as implied in the manual, so
> you don't mutate what you think you mutate?
>
Quite frequently. But if you mutate the array data, you mutate the array
data, no questions asked. What you definitely shouldn't do is grab a
pointer to your immutable (via pointer_from_objref) and try to mutate that
(but trying to grab a pointer to an immutable should become an error in a
future version of Julia anyways).


>
> 4. Does the generated code *not* use copies where it normally might, since
> it doesn't matter if the object is immutable, so again you don't mutate
> what you expected to?
>
This is possible. But it would require LLVM to decide that the array slot
itself couldn't have been re-assigned. Any intervening function call is
typically enough to block optimization on assuming the array data hasn't
changed. But TBAA (type-based alias analysis) is probably more likely to
bite you here, since LLVM won't consider the offset store to affect the
immutable type it lives inside.

>
> 1. and 2. require the GC to run during the lifetime of the mutated
> immutable, maybe you have been lucky and that hasn't happened ... yet.
>
> 3. and 4. the behaviour depends on what other use is made of the
> immutable, again maybe you have been lucky.
>
> As for passing immutables to C, well was always going to be risky, C just
> doesn't understand immutable.  If as suggested by Jameson mutables are
> layout compatible with C then the faster the habit of using immutables for
> that dies the better.
>
There's nothing risky about it. Types have the same layout and the same
behavior when getting passed to C regardless of whether they are declared
mutable or immutable. The ccall code hardly even checks the `.mutable`
field of the type (and that code hopefully will be deprecated soon, since
it doesn't really benefit the user).

Often, however, `immutable` provides a better representation of a C-struct
and is therefore necessary for compatibility (unless the only usages of the
type are by-pointer).

The updated documentation I mentioned above is part of my ccall-enhancement
pull request (which makes calling c functions that require or return
by-value structs actually work correctly). It can be read at:
https://github.com/JuliaLang/julia/blob/jn/ccall3/doc/manual/calling-c-and-fortran-code.rst
.

Regards.


>
> Train is approaching my stop, so thats enough for this rant.
>
> Cheers
> Lex
>
>
>>
>> 2015-02-09 15:15 GMT+01:00 Mauro <maur...@runbox.com>:
>>
> So, this actually modifies an immutable, right?  This doesn't seem
>>> right, aren't they supposed to be immutable?
>>>
>>> On Mon, 2015-02-09 at 14:29, Simon Danisch <sdan...@gmail.com> wrote:
>>> > You can actually modify immutables in an array directly. I actually
>>> > implemented this in GLAbstraction for my own usage.
>>> > I'm implementing FixedSizeArrays.jl
>>> > <https://github.com/SimonDanisch/FixedSizeArrays.jl> at the moment,
>>> which
>>> > will include this feature (In the feature list I call
>>> > it "setindex!/getindex for arrays of FSA (e.g. easy access to single
>>> > fields)")
>>> > This only works for immutables as it needs the tightly packed memory
>>> layout
>>> > of the array... Sadly, immutability doesn't occur in the type
>>> hierarchy, so
>>> > the setindex! that I'm talking about can't be written to work for any
>>> > immutable.
>>> > So this means, you either need to inherit from FixedSizeArrays to use
>>> this,
>>> > or copy the code (when it's transfered to fixedsizearrays).
>>> > Maybe we can open an issue at Julia, to see if we can get something
>>> like
>>> > this into base.
>>> >
>>> > Am Sonntag, 8. Februar 2015 21:35:20 UTC+1 schrieb vav...@uwaterloo.ca
>>> :
>>> >>
>>> >> I would like to request the following language feature: a function or
>>> >> macro to modify a field of an immutable inside a container.  Consider:
>>> >>
>>> >> immutable T
>>> >>   fielda::Int
>>> >>   fieldb::Int
>>> >>   fieldc::Int
>>> >> end
>>> >>
>>> >> function modify_fieldc!(x::Array{T,1}, sub::Int, newc::Int)
>>> >>    x[sub] = T(x[sub].fielda, x[sub].fieldb, newc)
>>> >> end
>>> >>
>>> >> This function modifies one field of an immutable object that sits
>>> inside a
>>> >> container.  The above construct, namely:
>>> >>    x[sub] = T(x[sub].field1, x[sub].field2, ... , newval, ...
>>> >> x[sub].fieldn)
>>> >> occurs rather frequently in my code.  It is not very readable and is
>>> also
>>> >> fragile in the case that I modify my code and put more fields in T
>>> later.
>>> >> It would be much nicer if there were a universal function like this:
>>> >>    modifyField!(x, sub, fieldc, newc)
>>> >>
>>> >> Note that I declared T to be 'immutable' rather than 'type' for
>>> >> performance reasons-- I prefer the data in the array x to be packed in
>>> >> memory rather than accessed with pointers.  If T were a 'type' then
>>> >> obviously the problem would go away.
>>> >>
>>> >> Maybe it is already possible to write a function or macro for this
>>> purpose
>>> >> in the existing language?
>>> >>
>>> >> Thanks,
>>> >> Steve Vavasis
>>> >>
>>> >>
>>>
>>>

Reply via email to