# Method that acts on union types, what is wrong?

What is wrong with this definition of a method that is thought to work on both types defined?

``````julia> struct A end

julia> struct B end

julia> function test( x :: T, y :: T ) where T <: Union{A,B}
true
end
test (generic function with 1 method)

julia> a = A() ; b = B();

julia> test(a,b)
ERROR: MethodError: no method matching test(::A, ::B)
Closest candidates are:
test(::T, ::T) where T<:Union{A, B} at REPL:1
Stacktrace:
 top-level scope at REPL:1

``````
1 Like

Ok, it is expecting that the type is the same for both variables. This works:

``````julia> function test( x :: T1, y :: T2 ) where {T1 <: Union{A,B}, T2 <: Union{A,B}}
true
end
test (generic function with 3 methods)

julia> test(a,b)
true

``````
2 Likes

If you don’t need the type parameter inside the function body, then you could just write that as this:

``````julia> function test(x::Union{A,B}, y::Union{A,B})
true
end
test (generic function with 1 method)

julia> test(a, b)
true
``````
4 Likes

No, I do not need it. But in my case we are talking of

``````Union{ComplexMixtures.Result,ComplexMixtures.Density,ComplexMixtures.Volume}
``````

writing this more than once is not fun. I guess nothing is wrong on using `:: T`, wright?

By the way, I am just writing an `isapprox` function that compares every field of a struct. Is there already a base function for that?

``````function isapprox( r1 :: T, r2 :: T ) where T <: Union{ComplexMixtures.Result,ComplexMixtures.Density,ComplexMixtures.Volume}
check = true
for field in fieldnames(typeof(r1))
x = getfield(r1,field)
y = getfield(r2,field)
if ! (x ≈ y)
check = false
println(" Data in \$field field differ. ")
end
end
return check
end
``````

Edit: Rs, I just realized that I do need the type , I was just using `typeof` instead 1 Like

why not define in your module:

``````const AMixture = Union{ComplexMixtures.Result,ComplexMixtures. ...}
``````

Then you can use `AMixture` in your definitions and Julia expands it to the longer term.

2 Likes

Yes, sure. Yet for the moment I only need that Union in exactly that point. That test function is the only requiring this type of input.

If you haven’t overloaded `getproperty`, you could use `propertynames`, which accepts an instance rather than a type:

``````propertynames(r1)
``````

Also, do you need to do an intersection of the field/property names for `r1` and `r2`?

By the way, that’s completely fine if it makes your code easier to write or read or maintain. You are free to write:

``````function foo(x)
println("the type of x is: ", typeof(x))
end
``````

``````function foo(x::T) where {T}
println("the type of x is: ", T)
end
``````

and you should expect to see little or no difference in the performance of your code (in fact, I suspect the compiler will generate exactly the same code in most cases). After all, if the compiler has access to the type of `x`, then it can insert the answer to `typeof(x)` without requiring any work to be done at runtime.

4 Likes

Oh, cool, I didn’t know about that.

I am not sure if I understand the question. I am actually comparing two instances of the same structs, and I want to be sure that all the data contained in them is the same (the result of a test case computation of the package). These structs contain other structs inside (of those 4 types of my program), such that that `isapprox` function runs for all the fields of everything.

Ah, I think now I understand your question: no, no, the fields are the same. If the structs where different of course that loop would have to be on the common fields of both structures only.

The original question was, actually, a result of me not knowing how the parametric type worked, because I was adding manually an error message to stop the execution if the two types were different. Thus, what I actually wanted was ` ( x :: T, y :: T ) where T <: Union{A,B}`, which will throw an error if the types are different.

1 Like