Defining array of constant values and prevent it to be modified inside functions

Hi,

I am trying to understand the best approach to pass an array of user input data into a function and make sure that this array is NEVER modified inside the function.

An example of what I would like to do is below:

julia> struct UserStruct
           data::Array{Float64}
       end

julia> test=UserStruct([1.0 2.0 3.0])   ## The idea is to have these values fixed always
UserStruct([1.0 2.0 3.0])

julia> println(test.data)
[1.0 2.0 3.0]

julia> function TestFun( x::UserStruct)
           x.data[1] = 10.0   ## I don't this to be allowed here
       end
TestFun (generic function with 1 method)

julia> TestFun(test)
10.0

julia> println(test.data)
[10.0 2.0 3.0]

Could someone provide some comments / resources on how to achieve this goal ? Thanks in advance !

Use StaticArrays? Or use fields of the type.

PS: probably use data::Vector{Float64}

1 Like

I think that’s the goal of this package: https://github.com/bkamins/ReadOnlyArrays.jl

This doesn’t prevent modification absolutely, but the intention (I believe) is to prevent accidental modification. For example, given a ReadOnlyArrays view, a function could use parent to get the original array which it could then modify.

4 Likes

You can wrap an array with a struct and define AbstractArray interface with custom setindex! to disallow mutation but this will never guarantee immutability because someone can still access fields of the struct directly. Then, also, suppress getproperty but there is also getfield.

1 Like

Perhaps a related question is: what exactly are you trying to protect against? Creating a custom AbstractArray with no setindex! will ensure that users cannot accidentally modify the internal data, and overloading getproperty can make it harder for them to accidentally peek at the underlying array, but it is always possible for a sufficiently motivated user to break things.

1 Like

Ok thanks everyone for the reply. Going through your answers it appears that there is no straightforward way to do what I am looking for (at least is not clear to me).

@rdeits, what I am trying to protect is to introduce unintentional bugs in my code. The user data will be passed into a quite large function that perform several operations using input data. I just thought that it would help to reduce the risk that something gets modified unintentionally.

Are you sure? ReadOnlyArrays.jl seems like it does exactly what you’re looking for:

julia> using ReadOnlyArrays

julia> struct UserStruct
         data::ReadOnlyArray{Float64, 1, Array{Float64, 1}}
       end

julia> test = UserStruct(ReadOnlyArray([1.0, 2.0, 3.0]))
UserStruct([1.0, 2.0, 3.0])

julia> test.data[1] = 2.0
ERROR: setindex! not defined for ReadOnlyArray{Float64,1,Array{Float64,1}}
3 Likes

@rdeits, thanks ! I see now that you are correct and that the solution can be obtained using the ReadOnlyArrays, as pointed out by @ericphanson

Thanks for showing it with an example, it made the point much easier to understand.

1 Like