# Is there a way to restrict two fields in a struct to either be both \`AbstractTypeA

**URL:** https://discourse.julialang.org/t/is-there-a-way-to-restrict-two-fields-in-a-struct-to-either-be-both-abstracttypea/55873
**Category:** General Usage
**Created:** [February 23, 2021, 6:21pm UTC](https://discourse.julialang.org/t/is-there-a-way-to-restrict-two-fields-in-a-struct-to-either-be-both-abstracttypea/55873 "2021-02-23T18:21:55Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![BridgeBot](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bridgebot/32/21491_2.png) [@BridgeBot](https://discourse.julialang.org/u/BridgeBot)
#### Post date: [February 23, 2021, 6:21pm UTC](https://discourse.julialang.org/t/is-there-a-way-to-restrict-two-fields-in-a-struct-to-either-be-both-abstracttypea/55873/1 "2021-02-23T18:21:55Z")

</div>

Is there a way to restrict two fields in a struct to either be both `AbstractTypeA` or both `AbstractTypeB`, but not necessarily the same concrete type?

Note that the original poster on Slack cannot see your response here on Discourse. Consider _transcribing the appropriate answer back to Slack_, or pinging the poster here on Discourse so they can _follow this thread_.  
[(Original message :slack:)](https://julialang.slack.com/archives/C6A044SQH/p1614104484215200?thread_ts=1614104484.215200&cid=C6A044SQH) [(More Info)](https://github.com/JuliaCommunity/SlackBridge)

---

<div class="post-metadata">

### Author: ![greg\_plowman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/greg_plowman/32/8100_2.png) [@greg\_plowman](https://discourse.julialang.org/u/greg_plowman)
#### Post date: [February 24, 2021, 7:34am UTC](https://discourse.julialang.org/t/is-there-a-way-to-restrict-two-fields-in-a-struct-to-either-be-both-abstracttypea/55873/2 "2021-02-24T07:34:34Z")

</div>

Seems like a good question.

I can’t see an easy way to do this. Here’s an initial attempt which is a bit convoluted but seems to work. Also not sure about the implementation of `common_supertype` function.

```julia
abstract type A end
abstract type B end
struct A1 <: A end
struct A2 <: A end
struct B1 <: B end
struct B2 <: B end

const Parents = Union{A,B}

#=
function common_supertype(x::X, y::Y) where {X, Y}
    return first(intersect(supertypes(X), supertypes(Y)))
end
=#

function common_supertype(x::X, y::Y) where {X, Y}
    supertypes_x = supertypes(X)
    i = findfirst(S -> y isa S, supertypes_x)
    return supertypes_x[i]
end

struct Bar{P<:Parents, X<:P, Y<:P}
    x::X
    y::Y
    Bar{P,X,Y}(x::X, y::Y) where {P<:Parents, X<:P, Y<:P} = new{P,X,Y}(x, y)
end

function Bar(x::X, y::Y) where {X,Y}
    P = common_supertype(x, y)
    P <: Parents || throw(ArgumentError("Cannot construct Bar(x::$X, y::$Y) where arguments do not have a common supertype"))
    Bar{P,X,Y}(x, y)
end

a1, a2 = A1(), A2()
b1, b2 = B1(), B2()

Bar(a1, a2)
Bar(b1, b2)
Bar(a1, b2)

```

---

<div class="post-metadata">

### Author: ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)
#### Post date: [February 24, 2021, 9:41am UTC](https://discourse.julialang.org/t/is-there-a-way-to-restrict-two-fields-in-a-struct-to-either-be-both-abstracttypea/55873/3 "2021-02-24T09:41:52Z")

</div>

Two solutions have been mentioned on slack.

One by @giordano using an extra type parameter:

```julia
julia> struct Foo{T<:Union{Integer,AbstractFloat}, A<:T, B<:T}
           a::A
           b::B
       end

julia> Foo{AbstractFloat,Float32,Float64}(1.0, 2.0)
Foo{AbstractFloat, Float32, Float64}(1.0f0, 2.0)

julia> Foo{Integer,UInt8,Int32}(1, 2)
Foo{Integer, UInt8, Int32}(0x01, 2)

julia> Foo{Integer,Float64,Int32}(1.0, 2)
ERROR: TypeError: in Foo, in A, expected A<:T<:Union{AbstractFloat, Integer}, got Type{Float64}
Stacktrace:
 [1] top-level scope
   @ REPL[4]:100:

```

One by @jakobnissen by ensuring type equality during construction:

```julia
struct Foo{A, B}
	x::A
	y::B
	function Foo{A, B}(x::A, y::B) where {A, B}
		if !((A <: Integer && B <: Integer) || (A <: AbstractFloat && B <: AbstractFloat))
			error("In Foo, Types A and B must have same supertype")
		end
		new{A, B}(x, y)
	end
end

```
