# SQL-like "trigger" for arrays within a struct

**URL:** <https://discourse.julialang.org/t/sql-like-trigger-for-arrays-within-a-struct/99177>\
**Category:** New to Julia\
**Tags:** question, arrays, views\
**Created:** [May 21, 2023, 4:15am UTC](https://discourse.julialang.org/t/sql-like-trigger-for-arrays-within-a-struct/99177 "2023-05-21T04:15:03Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![jwright11](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jwright11/32/32065_2.png) [@jwright11](https://discourse.julialang.org/u/jwright11)\
**Post date:** [May 21, 2023, 4:15am UTC](https://discourse.julialang.org/t/sql-like-trigger-for-arrays-within-a-struct/99177/1 "2023-05-21T04:15:03Z")

</div>

Is there such a thing as a SQL-like “trigger” for arrays within a struct in Julia? I have an immutable struct, foo, that stores lots of pieces of information which get consumed by other functions. Two of the elements of foo are “entangled.” The first piece is “data” (a nxm array that’s input by the user) and the second piece is “fcalc”, a nx(m-1) array that’s calculated by the code. Imagine something like this:

```julia
struct foo
    ...
    data
    fcalc
    ...
end

```

fcalc is simply the columns of data divided by the preceding columns of data, and to construct foo I do something like:

```julia
function create_foo(..., data,...)
    ...
    for j = 1:(size(data, 2) - 1)
        for i = 1:size(data, 1)
            fcalc[i, j] = data[i, j + 1] / data[i, j]
        end
    end
    ...
    return foo(..., data, fcalc,...)
end

```

foo is immutable but the elements of data are mutable, which is desirable, however, if data gets modified then fcalc needs to be updated. How can I ensure that happens? Is there a way to trigger the update of fcalc when an element of data is modified? Is it possible for fcalc to be a “calculated view?” Everything I’ve tried with view, @view, and @views has failed. Any suggestions or options I should explore?

---

<div class="post-metadata">

**Author:** ![Jollywatt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jollywatt/32/202198_2.png) [@Jollywatt](https://discourse.julialang.org/u/Jollywatt)\
**Post date:** [May 21, 2023, 5:46am UTC](https://discourse.julialang.org/t/sql-like-trigger-for-arrays-within-a-struct/99177/2 "2023-05-21T05:46:03Z")

</div>

There are a few ways you could refactor this code. Perhaps none are “fully automatic”, but I’d encourage you to consider each one in the wider context of your code.

1. Don’t precompute `fcalc`.

```julia
struct Foo
    ...
    data
    ...
end

fcalc(foo::Foo, i, j) = foo.data[i, j + 1]/foo.data[i, j]

```

1. Implement a “setter” for `data`.

```julia
struct Foo
    ...
    data
    fcalc
    ...
end
function set_data!(foo::Foo, data)
    for j = 1:(size(data, 2) - 1)
        for i = 1:size(data, 1)
            foo.fcalc[i, j] = data[i, j + 1] / data[i, j]
        end
    end
    foo.data .= data
end

```

You can even allow `foo.data = x` to call `set_data!(foo, x)` with

```julia
Base.setproperty!(foo::Foo, name::Symbol, x) = name === :data ? set_data!(foo, x) : setfield!(foo, name, x)

```

though this style is arguably less explicit, and direct mutation like `foo.data[i, j] = x` would not update `foo.fcalc`.

1. Roll your own lazy array type.

```julia
struct FcalcMatrix{T} <: AbstractMatrix{T}
    data::Matrix{T}
end

Base.size(fcm::FcalcMatrix) = size(fcm.data, 1), size(fcm.data, 2) - 1
Base.getindex(fcm::FcalcMatrix, i, j) = fcm.data[i, j + 1]/fcm.data[i, j]

struct Foo
    ...
    data
    fcalc
    ...
    Foo(..., data, ...) = new(..., data, FcalcMatrix(data), ...)
end

```

This last option is most similar to your attempts at using views, I think. The advantage is that you can do array operations with `fcalc` like matrix multiplication or aggregation as if it were a normal array (unlike option 1).

---

<div class="post-metadata">

**Author:** ![contradict](https://avatars.discourse-cdn.com/v4/letter/c/ac91a4/32.png) [@contradict](https://discourse.julialang.org/u/contradict)\
**Post date:** [May 22, 2023, 2:02am UTC](https://discourse.julialang.org/t/sql-like-trigger-for-arrays-within-a-struct/99177/3 "2023-05-22T02:02:04Z")

</div>

The correct answer is probably one of the ones in the above response, but if you are ok with a dependency, this is a neat library that is used extensively to make interactive plots with Makie:

> **[GitHub - JuliaGizmos/Observables.jl: observable refs](https://github.com/JuliaGizmos/Observables.jl)**
>
> observable refs. Contribute to JuliaGizmos/Observables.jl development by creating an account on GitHub.

---

<div class="post-metadata">

**Author:** ![jwright11](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jwright11/32/32065_2.png) [@jwright11](https://discourse.julialang.org/u/jwright11)\
**Post date:** [May 22, 2023, 1:52pm UTC](https://discourse.julialang.org/t/sql-like-trigger-for-arrays-within-a-struct/99177/4 "2023-05-22T13:52:17Z")

</div>

Thank you both for the suggestions! Option #3 and Observables.jl both look very promising. I think I need to do some benchmarking to really understand what’s best.
