I think the primary argument against inarg is that it is incredibly weak.
It is essentially only a self-imposed compile-time warning.

I'm not opposed to being able to prevent modification of an object, but I
think that is more useful as a requirement imposed by the caller, rather
than self imposed.

I thought some about adding a lock on array modification via the high bit
of the array size. This would make the additional check very low cost.

A module-level flag that forces all locals to be const by default (ala
Swift) sounds cool to me. As a general use language that is not primarily
targeted towards computer scientists, I expect that making the const option
a default would be a bit harder to explain to non-CS users.

I'm working on adding a Ref-type implementation to my jn/ccall3 pull
request (based on an implementation in use in Gtk.jl), because for
C-interop you often do need such a thing.

Being able to add const annotations to type fields would be beneficial,
especially when a constant-propagation pass is added to the function
inference code. I imagine that a pull-request to add such a feature would
be accepted.


On Wednesday, August 20, 2014, <[email protected]> wrote:

> Adam,
>
> I was the originator of this thread, and in the end I conceded that the
> current way that Julia handles immutable makes sense.  Indeed, I authored a
> paragraph about the definition of immutable composite types  for the 0.4.0
> version of the Julia manual in which I put Stefan's explanation dated Aug 5
> into my own words.
>
> I think that adding ref arg and value arg types to Julia would make the
> type system too confusing.  For example, what if you pass an Array of
> Arrays as a value arg?  (Are the inner arrays also copied over?)  Can you
> designate the elements of an Array to be ref/value?  And what about
> multiple dispatch in the case that two methods have similar signatures
> except for a difference in ref and value args?
>
> On a related note, I have proposed that Julia should have a way to
> designate that a mutable arg to function is an inarg (i.e., not
> modifiable).  My proposal is in a different thread in this newsgroup.  The
> consensus seems to be that the proposal works fine with existing Julia, but
> some respondents questioned whether the proposal would get buy-in.
>
> -- Steve Vavasis
>
>
>
> On Tuesday, August 5, 2014 5:38:17 PM UTC-4, [email protected] wrote:
>>
>> Dear Julia users,
>>
>> It seems to me that Julia's distinction between a 'type' and an
>> 'immutable' conflates two independent properties; the consequence of this
>> conflation is a needless loss of performance.  In more detail, the
>> differences between a 'type' struct and 'immutable' struct in Julia are:
>>
>> 1. Assignment of 'type' struct copies a pointer; assignment of an
>> 'immutable' struct copies the data.
>>
>> 2. An array of type structs is an array of pointers, while an array of
>> immutables is an array of data.
>>
>> 3. Type structs are refcounted, whereas immutables are not.  (This is not
>> documented; it is my conjecture.)
>>
>> 4. Fields in type structs can be modified, but fields in immutables
>> cannot.
>>
>> Clearly #1-#3 are related concepts.  As far as I can see, #4 is
>> completely independent from #1-#3, and there is no obvious reason why it is
>> forbidden to modify fields in immutables.  There is no analogous
>> restriction in C/C++.
>>
>> This conflation causes a performance hit.  Consider:
>>
>> type floatbool
>>   a::Float64
>>   b:Bool
>> end
>>
>> If t is of type Array{floatbool,1} and I want to update the flag b in
>> t[10] to 'true', I say 't[10].b=true' (call this 'fast'update).  But if
>> instead of 'type floatbool' I had said 'immutable floatbool', then to set
>> flag b in t[10] I need the more complex code t[10] =
>> floatbool(t[10].a,true) (call this 'slow' update).
>>
>> To document the performance hit, I wrote five functions below. The first
>> three use 'type' and either no update, fast update, or slow update; the
>> last two use 'immutable' and either no update or slow update.   You can see
>> a HUGE hit on performance between slow and fast update for `type'; for
>> immutable there would presumably also be a difference, although apparently
>> smaller. (Obviously, I can't test fast update for immutable; this is the
>> point of my message!)
>>
>> So why does Julia impose this apparently needless restriction on
>> immutable?
>>
>> -- Steve Vavasis
>>
>>
>> julia> @time testimmut.type_upd_none()
>> @time testimmut.type_upd_none()
>> elapsed time: 0.141462422 seconds (48445152 bytes allocated)
>>
>> julia> @time testimmut.type_upd_fast()
>> @time testimmut.type_upd_fast()
>> elapsed time: 0.618769232 seconds (48247072 bytes allocated)
>>
>> julia> @time testimmut.type_upd_slow()
>> @time testimmut.type_upd_slow()
>> elapsed time: 4.511306586 seconds (4048268640 bytes allocated)
>>
>> julia> @time testimmut.immut_upd_none()
>> @time testimmut.immut_upd_none()
>> elapsed time: 0.04480173 seconds (32229468 bytes allocated)
>>
>> julia> @time testimmut.immut_upd_slow()
>> @time testimmut.immut_upd_slow()
>> elapsed time: 0.351634871 seconds (32000096 bytes allocated)
>>
>> module testimmut
>>
>> type xytype
>>     x::Int
>>     y::Float64
>>     z::Float64
>>     summed::Bool
>> end
>>
>> immutable xyimmut
>>     x::Int
>>     y::Float64
>>     z::Float64
>>     summed::Bool
>> end
>>
>> myfun(x) = x * (x + 1) * (x + 2)
>>
>> function type_upd_none()
>>     n = 1000000
>>     a = Array(xytype, n)
>>     for i = 1 : n
>>         a[i] = xytype(div(i,2), 0.0, 0.0, false)
>>     end
>>     numtri = 100
>>     for tri = 1 : numtri
>>         sum = 0
>>         for i = 1 : n
>>             @inbounds x = a[i].x
>>             sum += myfun(x)
>>         end
>>     end
>> end
>>
>>
>> function type_upd_fast()
>>     n = 1000000
>>     a = Array(xytype, n)
>>     for i = 1 : n
>>         a[i] = xytype(div(i,2),  0.0, 0.0, false)
>>     end
>>     numtri = 100
>>     for tri = 1 : numtri
>>         sum = 0
>>         for i = 1 : n
>>             @inbounds x = a[i].x
>>             sum += myfun(x)
>>             @inbounds a[i].summed = true
>>         end
>>     end
>> end
>>
>> function type_upd_slow()
>>     n = 1000000
>>     a = Array(xytype, n)
>>     for i = 1 : n
>>         a[i] = xytype(div(i,2),  0.0, 0.0, false)
>>     end
>>     numtri = 100
>>     for tri = 1 : numtri
>>         sum = 0
>>         for i = 1 : n
>>             @inbounds x = a[i].x
>>             sum += myfun(x)
>>             @inbounds a[i] = xytype(a[i].x, a[i].y, a[i].z, true)
>>         end
>>     end
>> end
>>
>>
>> function immut_upd_none()
>>     n = 1000000
>>     a = Array(xyimmut, n)
>>     for i = 1 : n
>>         a[i] = xyimmut(div(i,2),  0.0, 0.0, false)
>>     end
>>     numtri = 100
>>     for tri = 1 : numtri
>>         sum = 0
>>         for i = 1 : n
>>             @inbounds x = a[i].x
>>             sum += myfun(x)
>>         end
>>     end
>> end
>>
>> function immut_upd_slow()
>>     n = 1000000
>>     a = Array(xyimmut, n)
>>     for i = 1 : n
>>         a[i] = xyimmut(div(i,2),  0.0, 0.0, false)
>>     end
>>     numtri = 100
>>     for tri = 1 : numtri
>>         sum = 0
>>         for i = 1 : n
>>             @inbounds x = a[i].x
>>             sum += myfun(x)
>>             @inbounds a[i] = xyimmut(a[i].x, a[i].y, a[i].z, true)
>>         end
>>     end
>> end
>>
>> end
>>
>>
>>
>>
>

Reply via email to