# Parameterize all types excluding a certain type

**URL:** <https://discourse.julialang.org/t/parameterize-all-types-excluding-a-certain-type/89639>\
**Category:** General Usage\
**Tags:** question, multidispatch\
**Created:** [November 2, 2022, 2:55am UTC](https://discourse.julialang.org/t/parameterize-all-types-excluding-a-certain-type/89639 "2022-11-02T02:55:48Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![HashBrown](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hashbrown/32/43601_2.png) [@HashBrown](https://discourse.julialang.org/u/HashBrown)\
**Post date:** [November 2, 2022, 2:55am UTC](https://discourse.julialang.org/t/parameterize-all-types-excluding-a-certain-type/89639/1 "2022-11-02T02:55:48Z")

</div>

Suppose I have a parameterized type `Foo{T}` with a field `val::T`, and an abstract type `Bar`. I would like to:

```julia
# Library Code
struct Foo{T}
    val::T
end

abstract type Bar end

baz(bar::Bar, a::Foo, b::Foo) = baz(bar, a.val, b.val)

# User Code
struct Bar1 <: Bar end

baz(bar::Bar1, a, b) = ...

```

This results in ambiguities because of multiple dispatch, but I would like my first method `baz` to call the second `baz` after unwrapping the `Foo`s. The first `baz` and the abstract type `Bar` would be library code, and the second `baz` and `Bar1` would be user code. However if I call `baz` with types `(Bar1, Foo, Foo)` it is ambiguous what I am calling.

A solution would be to define a `baz(bar::Bar1, a::Foo, b::Foo)` but like I said the first `baz` is library code and the type `Foo` is not exposed so this could only be done in the library code which can’t be done since the user is defining `Bar1`.

It seems another solution would be to define the second `baz` instead (not real code) like:

```julia
baz(bar::Bar1, a::Any-Foo, b::Any-Foo) = ...

```

where the syntax `Any-Foo` means any type that is not a `Foo`. That would resolve any ambiguities and the library could expose an alias for `Any-Foo` to be used in its place. Does such a concept exist? And if not what is the best way for me to solve my problem?

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [November 2, 2022, 3:26am UTC](https://discourse.julialang.org/t/parameterize-all-types-excluding-a-certain-type/89639/2 "2022-11-02T03:26:28Z")

</div>

I’m not quite sure I get the use case, since these two parts seem inconsistent:

> [@HashBrown](#):
>
> if I call `baz` with types `(Bar1, Foo, Foo)` it is ambiguous what I am calling.

> [@HashBrown](#):
>
> the type `Foo` is not exposed

The user can’t call `baz` with the types `(Bar1, Foo, Foo)` if the type `Foo` is not exposed.

And if they call it with the types `(Bar, S, T)`, where `S` and `T` are not `Foo`, then there is no ambiguity, and your method for `baz` doesn’t come into play at all.

---

<div class="post-metadata">

**Author:** ![HashBrown](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hashbrown/32/43601_2.png) [@HashBrown](https://discourse.julialang.org/u/HashBrown)\
**Post date:** [November 2, 2022, 3:46am UTC](https://discourse.julialang.org/t/parameterize-all-types-excluding-a-certain-type/89639/3 "2022-11-02T03:46:37Z")

</div>

The library code calls `baz` with types `(Bar1, Foo, Foo)`. The user defined the concrete type `Bar1` which the library uses, only knowing that the user has provided some concrete implementation of `Bar`.

The user calls some other code in the library with a `Bar1` and some other stuff. The library later creates `Foo`s that wrap that other stuff, and then calls `baz` with `(Bar1, Foo, Foo)`. I want that library call to resolve to the library definition which should then call the user definition after unwrapping to provide generic and extensible code.

---

<div class="post-metadata">

**Author:** ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)\
**Post date:** [November 2, 2022, 7:53am UTC](https://discourse.julialang.org/t/parameterize-all-types-excluding-a-certain-type/89639/4 "2022-11-02T07:53:57Z")

</div>

In that case, I would probably just use a different function within the library, i.e.,

```julia
function _baz(bar::Bar, a::Foo, b::Foo) # internal and only called from library code
    baz(bar, a.val, b.val) # part of the external interface and extendable by user code
end

```

Are there any reasons, why this would not work in your case?

---

<div class="post-metadata">

**Author:** ![HashBrown](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hashbrown/32/43601_2.png) [@HashBrown](https://discourse.julialang.org/u/HashBrown)\
**Post date:** [November 2, 2022, 1:32pm UTC](https://discourse.julialang.org/t/parameterize-all-types-excluding-a-certain-type/89639/5 "2022-11-02T13:32:01Z")

</div>

I don’t want to do that because in this case my `baz` function is actually `Base.Order.lt(o:Base.Order.Ordering, a, b)`. I could have the user define `_lt` (can’t do it in the library because it has to be `lt` there), but I’d rather use the built in mechanism for ordering.

The current solution on my mind is to expose a macro that defines a `baz(bar::Bar1, a::Foo, b::Foo)` with the unwrapping behavior when the user defines `@custom_baz baz(bar::Bar1, a, b)`. That way `Foo` is still not exposed to the user. I don’t love this solution either though and feel there should be some other way if you have any other suggestions?

---

<div class="post-metadata">

**Author:** ![HashBrown](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hashbrown/32/43601_2.png) [@HashBrown](https://discourse.julialang.org/u/HashBrown)\
**Post date:** [November 2, 2022, 2:35pm UTC](https://discourse.julialang.org/t/parameterize-all-types-excluding-a-certain-type/89639/6 "2022-11-02T14:35:01Z")

</div>

Just for completeness I am posting the macro I am talking about here:

```julia
macro custom_order(lt_func)
      ordering_type = lt_func.args[1].args[2].args[1]
      unwrap_node_lt_func = quote
          Base.Order.lt(
              o::$ordering_type, 
              a::MergedIterators.MergedIteratorStateNode, 
              b::MergedIterators.MergedIteratorStateNode
          ) = Base.Order.lt(o, a.value, b.value)
      end
  
      quote
          $(esc(lt_func))
          $(esc(unwrap_node_lt_func))
      end
end

```

Here `lt_func` is the user defined `baz`. `unwrap_node_lt_func` is an auto-defined method to remove ambiguity. It ends up being defined by the user through the use of the library provided macro. `MergedIterator.MergedIteratorStateNode` is `Foo`. And finally `ordering_type` is `Bar1`.

Example use would be:

```julia
struct AbsOrder <: Base.Order.Ordering end
@custom_order Base.Order.lt(::AbsOrder, a, b) = Base.Order.lt(Base.Order.Forward, abs(a), abs(b))

```

---

<div class="post-metadata">

**Author:** ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)\
**Post date:** [November 2, 2022, 6:32pm UTC](https://discourse.julialang.org/t/parameterize-all-types-excluding-a-certain-type/89639/7 "2022-11-02T18:32:22Z")

</div>

Ok, that makes it more difficult. Guess that the following should work though:

```julia
# Library Code
struct Foo{T}
    val::T
end

abstract type Bar end

_baz(bar::Bar, a::Foo, b::Foo) = _baz(bar, a.val, b.val)
# Library code always calls _baz, but forwards it to baz if no more special version is available
_baz(x, a, b) = baz(x, a, b)

# User Code
struct Bar1 <: Bar end

# User extends baz, i.e., no the dispatch within the library (on _baz) is ever in conflict with user methods
baz(bar::Bar1, a, b) = ...

```
