# Best practices for including data in a module as a constant array

**URL:** <https://discourse.julialang.org/t/best-practices-for-including-data-in-a-module-as-a-constant-array/11077>\
**Category:** General Usage\
**Created:** [May 22, 2018, 4:56pm UTC](https://discourse.julialang.org/t/best-practices-for-including-data-in-a-module-as-a-constant-array/11077 "2018-05-22T16:56:05Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![ajkeith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ajkeith/32/970_2.png) [@ajkeith](https://discourse.julialang.org/u/ajkeith)\
**Post date:** [May 22, 2018, 4:56pm UTC](https://discourse.julialang.org/t/best-practices-for-including-data-in-a-module-as-a-constant-array/11077/1 "2018-05-22T16:56:05Z")

</div>

I’m having trouble finding the best way to include data in a module. Basically I have a small array (5 x 5) of constant data, but to interface with other packages, I want to define a function that just returns the element in the constant array at a given index.

From what I can tell, defining a constant array in the global scope of the module isn’t possible. Is that right? Is the best way to just define the data as a normal global array and then reference it inside my function? I can’t think of any other way to avoid having an array in the global scope of the module.

I ran some mini-benchmarks and it looks way more expensive to define the array inside the function (not surprisingly). Is there a better way to include constant data in a module than using a globally defined array?

Here’s a minimal working example that shows the difference between the global and local approach, with some quick `@btime` benchmarks.

```julia
using BenchmarkTools

# data defined globally
data_outer = [1.0 2.0; 3.0 4.0]
f_outer(x,y) = data_outer[x, y]

# data redefined inside function
function f_inner(x,y)
    data_inner = [1.0 2.0; 3.0 4.0]
    data_inner[x, y]
end

# large data defined globally
data_outer_large = rand(1_000, 1_000)
f_outer_large(x,y) = data_outer_large[x, y]

# large data redefined inside function
function f_inner_large(x,y)
    data_inner_large = rand(1_000, 1_000)
    data_inner_large[x, y]
end

```

```julia
julia> @btime f_outer(1,2)
  26.666 ns (1 allocation: 16 bytes)
2.0

julia> @btime f_inner(1,2)
  41.318 ns (1 allocation: 112 bytes)
2.0

julia> @btime f_outer_large(1,2)
  28.890 ns (1 allocation: 16 bytes)
0.6037250079523222

julia> @btime f_inner_large(1,2)
  4.157 ms (2 allocations: 7.63 MiB)
0.36772602420929323

```

---

<div class="post-metadata">

**Author:** ![ExpandingMan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/expandingman/32/866_2.png) [@ExpandingMan](https://discourse.julialang.org/u/ExpandingMan)\
**Post date:** [May 22, 2018, 5:05pm UTC](https://discourse.julialang.org/t/best-practices-for-including-data-in-a-module-as-a-constant-array/11077/2 "2018-05-22T17:05:06Z")

</div>

> [@ajkeith](#):
>
> From what I can tell, defining a constant array in the global scope of the module isn’t possible.

Huh? It’s definitely possible. Why do you think it isn’t?

```julia
const data_outer = [1.0 2.0; 3.0 4.0]

```

should work just fine. Is there some other piece to this that I’m missing?

---

<div class="post-metadata">

**Author:** ![ajkeith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ajkeith/32/970_2.png) [@ajkeith](https://discourse.julialang.org/u/ajkeith)\
**Post date:** [May 22, 2018, 5:25pm UTC](https://discourse.julialang.org/t/best-practices-for-including-data-in-a-module-as-a-constant-array/11077/3 "2018-05-22T17:25:59Z")

</div>

Okay that definitely works, thanks - I should have benchmarked against that in the first place:

```julia
# global data
data = rand(10_000, 10_000)
f(x,y) = data[x, y]

# constant global data
const data_const = rand(10_000, 10_000)
f_const(x,y) = data_const[x, y]

@btime f(1,2) # 26.256 ns (1 allocation: 16 bytes)
@btime f_const(1,2) # 2.051 ns (0 allocations: 0 bytes)

```

My confusion was coming from the behavior that re-defining a scalar constant throws a warning but re-defining an element in a vector constant doesn’t throw a warning. I did some googling and came across this (very dated) [issue](https://github.com/JuliaLang/julia/issues/317) which made me think that I wouldn’t get any additional performance.

---

<div class="post-metadata">

**Author:** ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)\
**Post date:** [May 22, 2018, 5:43pm UTC](https://discourse.julialang.org/t/best-practices-for-including-data-in-a-module-as-a-constant-array/11077/4 "2018-05-22T17:43:29Z")

</div>

This may be a premature optimization, but it’s worth checking out [StaticArrays.jl](https://github.com/JuliaArrays/StaticArrays.jl) for cases like this:

**edit: it’s fast, but wildly unsafe, with a risk of segfaults**

```julia
using StaticArrays

const stackdata = @SArray(rand(5,5))
const heapdata = rand(5,5)

getstack(i,j) = @inbounds stackdata[i,j]
getheap(i,j) = @inbounds heapdata[i,j]

```

```julia
julia> using BenchmarkTools

julia> @btime getstack(1,2)
  0.042 ns (0 allocations: 0 bytes)

julia> @btime getheap(1,2)
  1.550 ns (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![ExpandingMan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/expandingman/32/866_2.png) [@ExpandingMan](https://discourse.julialang.org/u/ExpandingMan)\
**Post date:** [May 22, 2018, 5:46pm UTC](https://discourse.julialang.org/t/best-practices-for-including-data-in-a-module-as-a-constant-array/11077/5 "2018-05-22T17:46:30Z")

</div>

Oh, I see, I missed that you were trying to mutate it.

---

<div class="post-metadata">

**Author:** ![NiclasMattsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/niclasmattsson/32/21988_2.png) [@NiclasMattsson](https://discourse.julialang.org/u/NiclasMattsson)\
**Post date:** [May 22, 2018, 10:00pm UTC](https://discourse.julialang.org/t/best-practices-for-including-data-in-a-module-as-a-constant-array/11077/6 "2018-05-22T22:00:27Z")

</div>

> [@](#):
>
> ```julia
> using StaticArrays
> 
> const stackdata = @SArray(rand(5,5))
> const heapdata = rand(5,5)
> 
> getstack(i,j) = @inbounds stackdata[i,j]
> getheap(i,j) = @inbounds heapdata[i,j]
> 
> ```

Hmmm… isn’t that a wildly reckless way of using `@inbounds`, especially in a thread titled “Best practices”? 🙂

Just out of curiosity, is a segfault the worst thing that can happen from this or can it open up for arbitrary code execution down the road? Or maybe fry the nearest nuclear power plant?

---

<div class="post-metadata">

**Author:** ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)\
**Post date:** [May 22, 2018, 11:22pm UTC](https://discourse.julialang.org/t/best-practices-for-including-data-in-a-module-as-a-constant-array/11077/7 "2018-05-22T23:22:32Z")

</div>

You’re absolutely right–careless use of `@inbounds` is dangerous, and even more so for a user-facing function. A segfault’s probably the worst that could happen, though, since the function is read-only.

---

<div class="post-metadata">

**Author:** ![Keno](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/keno/32/285_2.png) [@Keno](https://discourse.julialang.org/u/Keno)\
**Post date:** [May 23, 2018, 1:23am UTC](https://discourse.julialang.org/t/best-practices-for-including-data-in-a-module-as-a-constant-array/11077/8 "2018-05-23T01:23:02Z")

</div>

> [@stillyslalom](#):
>
> A segfault’s probably the worst that could happen, though, since the function is read-only.

This is a bad assumption. Out of bounds accesses are undefined behavior, so LLVM may happily delete the entire code path calling this function with out of bounds indicies.
