# Traits and type piracy

**URL:** <https://discourse.julialang.org/t/traits-and-type-piracy/112516>\
**Category:** General Usage\
**Tags:** traits, type-piracy\
**Created:** [April 4, 2024, 10:47am UTC](https://discourse.julialang.org/t/traits-and-type-piracy/112516 "2024-04-04T10:47:56Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![pat-alt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pat-alt/32/34264_2.png) [@pat-alt](https://discourse.julialang.org/u/pat-alt)\
**Post date:** [April 4, 2024, 10:47am UTC](https://discourse.julialang.org/t/traits-and-type-piracy/112516/1 "2024-04-04T10:47:56Z")

</div>

**TLDR** : I’m defining a trait in a meta package A and trying to assign the trait in a package B that imports A. This causes type piracy and I don’t know how to resolve it.

**Background** : Inspired by other examples such as MLJBase, I’ve recently added a meta package to our Taija ecosystem: [TaijaBase](https://github.com/JuliaTrustworthyAI/TaijaBase.jl). I want to use this package to define common functionality, types and traits that are used by multiple packages in our ecosystem.

**Specific Issue** : TaijaBase (package A) currently [defines](https://github.com/JuliaTrustworthyAI/TaijaBase.jl/blob/08f1e1cb63dab5ce79be5f5f4984ae345bbf73b8/src/parallelization/traits.jl#L1) a trait that can be used to determine whether at function can be parallelized using [TaijaParallel](https://github.com/JuliaTrustworthyAI/TaijaParallel.jl) (package B) or not. By default, all objects are defined as `NotParallel`:

```julia
"A base type for a style of process."
abstract type ProcessStyle end

"By default all types have this trait."
struct NotParallel <: ProcessStyle end
ProcessStyle(::Type) = NotParallel()

"Processes that can be parallelized have this trait."
struct IsParallel <: ProcessStyle end

# Implementing trait behaviour:
parallelizable(x::T) where {T} = parallelizable(ProcessStyle(T), x)
parallelizable(::IsParallel, x) = true
parallelizable(::NotParallel, x) = false

```

In TaijaParallel, I am trying to overload the `ProcessStyle` function like so:

```julia
import TaijaBase

"The `generate_counterfactual` method is parallelizable."
TaijaBase.ProcessStyle(
    ::Type{<:typeof(CounterfactualExplanations.generate_counterfactual)},
) = TaijaBase.IsParallel()

"The `evaluate` function is parallelizable."
function TaijaBase.ProcessStyle(
    ::Type{<:typeof(CounterfactualExplanations.Evaluation.evaluate)},
)
    return TaijaBase.IsParallel()
end

```

According to Aqua.jl, this amounts to type piracy:

```julia-repl
julia> using TaijaParallel, Test

julia> using Aqua
       
       @testset "Aqua.jl" begin
           # Ambiguities needs to be tested seperately until the bug in Aqua package (https://github.com/JuliaTesting/Aqua.jl/issues/77) is fixed
           Aqua.test_ambiguities([TaijaParallel]; recursive = false, broken = false)
       
           Aqua.test_all(TaijaParallel; ambiguities = false)
       end
┌ Warning: Package cuDNN not found in current path.
│ - Run `import Pkg; Pkg.add("cuDNN")` to install the cuDNN package, then restart julia.
│ - If cuDNN is not installed, some Flux functionalities will not be available when running on the GPU.
└ @ FluxCUDAExt ~/.julia/packages/Flux/Wz6D4/ext/FluxCUDAExt/FluxCUDAExt.jl:57
┌ Warning: Package cuDNN not found in current path.
│ - Run `import Pkg; Pkg.add("cuDNN")` to install the cuDNN package, then restart julia.
│ - If cuDNN is not installed, some Flux functionalities will not be available when running on the GPU.
└ @ FluxCUDAExt ~/.julia/packages/Flux/Wz6D4/ext/FluxCUDAExt/FluxCUDAExt.jl:57
Possible type-piracy detected:
[1] TaijaBase.ProcessStyle(::Type{<:typeof(CounterfactualExplanations.generate_counterfactual)}) @ TaijaParallel ~/code/TaijaParallel.jl/src/CounterfactualExplanations.jl/assign_traits.jl:4
[2] TaijaBase.ProcessStyle(::Type{<:typeof(CounterfactualExplanations.Evaluation.evaluate)}) @ TaijaParallel ~/code/TaijaParallel.jl/src/CounterfactualExplanations.jl/assign_traits.jl:9
Piracy: Test Failed at /Users/paltmeyer/.julia/packages/Aqua/OTNBC/src/piracies.jl:240
  Expression: isempty(v)
   Evaluated: isempty(Method[TaijaBase.ProcessStyle(::Type{<:typeof(CounterfactualExplanations.generate_counterfactual)}) @ TaijaParallel ~/code/TaijaParallel.jl/src/CounterfactualExplanations.jl/assign_traits.jl:4, TaijaBase.ProcessStyle(::Type{<:typeof(CounterfactualExplanations.Evaluation.evaluate)}) @ TaijaParallel ~/code/TaijaParallel.jl/src/CounterfactualExplanations.jl/assign_traits.jl:9])

Stacktrace:
 [1] macro expansion
   @ ~/.julia/juliaup/julia-1.10.2+0.aarch64.apple.darwin14/share/julia/stdlib/v1.10/Test/src/Test.jl:672 [inlined]
 [2] test_piracies(m::Module; broken::Bool, kwargs::@Kwargs{})
   @ Aqua ~/.julia/packages/Aqua/OTNBC/src/piracies.jl:240
 [3] test_piracies
   @ ~/.julia/packages/Aqua/OTNBC/src/piracies.jl:217 [inlined]
 [4] macro expansion
   @ ~/.julia/packages/Aqua/OTNBC/src/Aqua.jl:100 [inlined]
 [5] macro expansion
   @ ~/.julia/juliaup/julia-1.10.2+0.aarch64.apple.darwin14/share/julia/stdlib/v1.10/Test/src/Test.jl:1577 [inlined]
 [6] test_all(testtarget::Module; ambiguities::Bool, unbound_args::Bool, undefined_exports::Bool, project_extras::Bool, stale_deps::Bool, deps_compat::Bool, piracies::Bool, persistent_tasks::Bool)
   @ Aqua ~/.julia/packages/Aqua/OTNBC/src/Aqua.jl:99
Test Summary: | Pass Fail Total Time
Aqua.jl | 10 1 11 18.2s
  Method ambiguity | None 0.0s
  Unbound type parameters | 1 1 0.0s
  Undefined exports | 1 1 0.0s
  Compare Project.toml and test/Project.toml | 1 1 0.0s
  Stale dependencies | 1 1 3.2s
  Compat bounds | 4 4 0.1s
  Piracy | 1 1 0.4s
  Persistent tasks | 1 1 9.4s
ERROR: Some tests did not pass: 10 passed, 1 failed, 0 errored, 0 broken.

```

How should I go about this? Any advice would be much appreciated!

Many thanks,

Pat

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [April 4, 2024, 11:13am UTC](https://discourse.julialang.org/t/traits-and-type-piracy/112516/2 "2024-04-04T11:13:58Z")

</div>

> [@pat-alt](#):
>
> According to [Aqua.jl](https://juliahub.com/ui/Packages/General/Aqua), this amounts to type piracy:

Aqua is right, because `TaijaParallel` owns

- neither `TaijaBase.ProcessStyle`
- nor `CounterfactualExplanations.generate_counterfactual` / `CounterfactualExplanations.Evaluation.evaluate`

> [@pat-alt](#):
>
> How should I go about this? Any advice would be much appreciated!

Maybe a package extension to `TaijaBase` that depends on `CounterfactualExplanations`?

---

<div class="post-metadata">

**Author:** ![haberdashPI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/haberdashpi/32/26337_2.png) [@haberdashPI](https://discourse.julialang.org/u/haberdashPI)\
**Post date:** [April 4, 2024, 12:12pm UTC](https://discourse.julialang.org/t/traits-and-type-piracy/112516/3 "2024-04-04T12:12:43Z")

</div>

Since you are defining the trait yourself you could solve this by having a second (optional) context argument. You can see an example in [GitHub - beacon-biosignals/StableHashTraits.jl: Compute hashes over any Julia object simply and reproducibly](https://github.com/beacon-biosignals/StableHashTraits.jl) (read the section on customizing contexts)

---

<div class="post-metadata">

**Author:** ![pat-alt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pat-alt/32/34264_2.png) [@pat-alt](https://discourse.julialang.org/u/pat-alt)\
**Post date:** [April 4, 2024, 12:27pm UTC](https://discourse.julialang.org/t/traits-and-type-piracy/112516/4 "2024-04-04T12:27:31Z")

</div>

Ok, thanks both! I think I’ll go with the first solution by @gdalle but instead define this trait in TaijaParallel (where it probably belongs anyway). But adding a context argument is also an interesting idea, thank you very much.
