# Structure type + in place modification of columns of arrays

**URL:** <https://discourse.julialang.org/t/structure-type-in-place-modification-of-columns-of-arrays/64275>\
**Category:** New to Julia\
**Tags:** type, mutable-structure\
**Created:** [July 8, 2021, 12:27pm UTC](https://discourse.julialang.org/t/structure-type-in-place-modification-of-columns-of-arrays/64275 "2021-07-08T12:27:49Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![dmetivie](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dmetivie/32/6926_2.png) [@dmetivie](https://discourse.julialang.org/u/dmetivie)\
**Post date:** [July 8, 2021, 12:27pm UTC](https://discourse.julialang.org/t/structure-type-in-place-modification-of-columns-of-arrays/64275/1 "2021-07-08T12:27:49Z")

</div>

In this post, I have two questions I am not sure are completely separate or not, so I ask them both here.

1. 

I define a structure and a substructure that has a field `B` which is an array of `Distributions`. It can be univariate, product, multivariate etc.  
I define the structure like that

```julia
using Distributions
abstract type mainT{F<:VariateForm} end

struct SubT{F} <: mainT{F}
    B::AbstractArray{Distribution{F}}
end

```

However, when I try to define a `SubT` from an array of `Bernoulli` it does not work

```julia
K = 5
T = 2
B = Bernoulli.(rand(K,T)) # Array of Bernoulli distributions
h = SubT(B) # Fail
ERROR: MethodError: no method matching SubT(::Matrix{Bernoulli{Float64}})
Closest candidates are:
  SubT(::AbstractArray{Distribution{F, S} where S<:ValueSupport, N} where N) where F at REPL[3]:2

```

So I can do the following to make it work

```julia
B = convert(Matrix{UnivariateDistribution{S} where S<:ValueSupport}, B)
h = SubT2(B) # Works

```

This type re-definition is problematic for many reason so I would like to avoid and be able to define my `h` the first way. Ideally, the type of `h` would not be `UnivariateDistribution{S} where S<:ValueSupport`but specific to each choice of distribution, e.g. here `Matrix{Bernoulli{Float64}}`.

1. 

The second problem is, when I want to sort columns of my array in some specific way with in place modification. I have the function

```julia
function sort_wrt_ref!(B::AbstractVector)
	K = size(B, 1)
	sorting = [succprob(h.B[k]) for k in 1:K]
	B[:] = B[sortperm(sorting)]
end

```

However, it does not seem to modify in place the columns of my array.

```julia
julia> h.B
5×2 Matrix{UnivariateDistribution{S} where S<:ValueSupport}:
 Bernoulli{Float64}(p=0.958907) Bernoulli{Float64}(p=0.204364)
 Bernoulli{Float64}(p=0.0382291) Bernoulli{Float64}(p=0.898818)
 Bernoulli{Float64}(p=0.953247) Bernoulli{Float64}(p=0.367522)
 Bernoulli{Float64}(p=0.196388) Bernoulli{Float64}(p=0.0861771)
 Bernoulli{Float64}(p=0.333265) Bernoulli{Float64}(p=0.275637)

julia> sort_wrt_ref!(h.B[:,1]) # it is sorting as the output shows but not changing the column h.B[:,1]
5-element Vector{UnivariateDistribution{S} where S<:ValueSupport}:
 Bernoulli{Float64}(p=0.038229098624871005)
 Bernoulli{Float64}(p=0.1963878250239648)
 Bernoulli{Float64}(p=0.3332646196249027)
 Bernoulli{Float64}(p=0.9532465128727561)
 Bernoulli{Float64}(p=0.958907107799279)

julia> h.B
5×2 Matrix{UnivariateDistribution{S} where S<:ValueSupport}:
 Bernoulli{Float64}(p=0.958907) Bernoulli{Float64}(p=0.204364)
 Bernoulli{Float64}(p=0.0382291) Bernoulli{Float64}(p=0.898818)
 Bernoulli{Float64}(p=0.953247) Bernoulli{Float64}(p=0.367522)
 Bernoulli{Float64}(p=0.196388) Bernoulli{Float64}(p=0.0861771)
 Bernoulli{Float64}(p=0.333265) Bernoulli{Float64}(p=0.275637)

```

I have the same issue with other in place function. They work as expected on `vector` but not on slice of array.

---

<div class="post-metadata">

**Author:** ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)\
**Post date:** [July 8, 2021, 1:55pm UTC](https://discourse.julialang.org/t/structure-type-in-place-modification-of-columns-of-arrays/64275/2 "2021-07-08T13:55:25Z")

</div>

For your first problem, you are looking for:

```julia
struct SubT1{F, N}
    # Not AbstractArray - use a concrete type
    # The eltype of B is a subtype of Distribution
    B :: Array{<: Distribution{F}, N}
end

K = 5
T = 2
B = Bernoulli.(rand(K,T))

h = SubT1(B)

```

---

<div class="post-metadata">

**Author:** ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)\
**Post date:** [July 8, 2021, 2:08pm UTC](https://discourse.julialang.org/t/structure-type-in-place-modification-of-columns-of-arrays/64275/3 "2021-07-08T14:08:38Z")

</div>

For your second problem, the issue is that `B[:, 1]` creates a copy of that column. One solution is to sort a `@view` instead. MWE:

```julia
julia> B0 = [4 3; 2 1];

julia> function sort_wrt_ref!(B::AbstractVector{F}) where F
               K = size(B, 1)
               B[:] = B[sortperm(B)]
       end
sort_wrt_ref! (generic function with 1 method)

julia> B = copy(B0);

julia> sort_wrt_ref!(B[:, 1])
2-element Vector{Int64}:
 2
 4

julia> @show B
B = [4 3; 2 1]
2×2 Matrix{Int64}:
 4 3
 2 1

julia> B = copy(B0);

julia> sort_wrt_ref!(@view B[:, 1])
2-element Vector{Int64}:
 2
 4

julia> @show B
B = [2 3; 4 1]
2×2 Matrix{Int64}:
 2 3
 4 1

```

---

<div class="post-metadata">

**Author:** ![dmetivie](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dmetivie/32/6926_2.png) [@dmetivie](https://discourse.julialang.org/u/dmetivie)\
**Post date:** [July 8, 2021, 6:16pm UTC](https://discourse.julialang.org/t/structure-type-in-place-modification-of-columns-of-arrays/64275/4 "2021-07-08T18:16:45Z")

</div>

Thanks that works!

1. Why should one use a concrete type instead of Abstract type?
2. Ok.

---

<div class="post-metadata">

**Author:** ![bencherian](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bencherian/32/18025_2.png) [@bencherian](https://discourse.julialang.org/u/bencherian)\
**Post date:** [July 8, 2021, 6:35pm UTC](https://discourse.julialang.org/t/structure-type-in-place-modification-of-columns-of-arrays/64275/5 "2021-07-08T18:35:24Z")

</div>

Your first problem occurs because `Matrix{Bernoulli{Float64}}` is not a subtype of `AbstractArray{Distribution}` Just like `Array{Float64}` is not a subtype of `AbstractArray{Real}`. The key change is the use of `{<:Distribution{F}}` as opposed to your original definition.

I don’t think the change from `AbstractArray` to `Array` is strictly necessary for the code to run, but generally, you want to avoid putting abstract types in structs for performance reasons since it adds an extra layer of indirection every time you access a structure member.
