# Is dispatch on another type's parameter (::NotMyType{MyType}) piracy?

**URL:** <https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797>\
**Category:** General Usage\
**Created:** [February 26, 2024, 5:16pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797 "2024-02-26T17:16:47Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [February 26, 2024, 5:16pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797/1 "2024-02-26T17:16:47Z")

</div>

> [@Unsure about properties](https://discourse.julialang.org/t/unsure-about-properties/110756/3):
>
> `S` is yours, but not `typeof(S)`

> [@Unsure about properties](https://discourse.julialang.org/t/unsure-about-properties/110756/4):
>
> even if you own `S` you don’t own `Type{S}`

> [@Unsure about properties](https://discourse.julialang.org/t/unsure-about-properties/110756/5):
>
> it’s starting to sink in that I don’t own `Type{S}` because I don’t own `Type`

Actually, does this follow? Assuming we write a definition for `S` as opposed to aliasing a `Union` for example, `typeof(S)` would be `DataType` or `UnionAll`, which along with the parametric `Type` are definitely owned by Base. But if we own `S`, is `Type{S}` really owned by Base? The concepts of ownership and type piracy are intended to prevent independent packages from interfering with other’s method dispatch, e.g. `*(::Symbol, ::Symbol)` is a possible call signature without your package (specifically unimplemented in `Base` alone) so you shouldn’t implement it. However, `convert(::Type{S}, ::Symbol)` requires your package’s `S` definition. Moreover that seems like an idiomatic `Base.convert` method.

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [February 26, 2024, 4:05pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797/2 "2024-02-26T16:05:50Z")

</div>

> [@Unsure about properties](https://discourse.julialang.org/t/unsure-about-properties/110756/11):
>
> Actually, does this follow?

I think it does (but I’m no authority). When you implement a new type `SomeType{T}` and define functions to manipulate it, you need to know that these functions do what you wrote, also internally, not just at the surface exposed to the user.

Consider this example:

```julia
mutable struct S{T}
    x::T
    y::T
    a::Union{Missing,T} # value to be cached
    S(x::T,y::T) where T = new{T}(x, y, missing)
end

function get_a(s::S)
    if ismissing(s.a)
        s.a = expensive_function(s.x, s.y)
    end
    return s.a
end

function get_b(s::S)
    get_a(s) # Make sure `a` is cached
    return s.a * s.a;
end

```

I don’t want to document that `get_b` is going to call `get_a` to populate the cached value of `a`. This is all internal stuff, but I should be able to depend on it when I implement my own functions on my own types. Also in the case of parametric types. So it makes sense to me that users are not allowed to define `get_a(s::S{CustomType})` even if they own `CustomType`.

Of course it’s fine if I document that it’s allowed (as in the `convert` case).

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [February 26, 2024, 4:19pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797/3 "2024-02-26T16:19:49Z")

</div>

> [@Unsure about properties](https://discourse.julialang.org/t/unsure-about-properties/110756/5):
>
> I think it’s starting to sink in that I don’t own `Type{S}` because I don’t own `Type`.

Whether or not defining these properties is a good idea (unlikely) I don’t see how defining methods on `NotMyType{MyType}` is piracy.

It might not be a good idea, mind you: people generally expect that `NotMyType` will behave in a consistent way, and it’s bad form to go against the grain that way.

But `notmymethod(t::NotMyType{MyType})` can’t affect code you don’t own, which is the definition of type piracy. Any other `notmymethod(t:NotMyType)` is either less specific or concretely different from that signature, so this cannot change the method resolved in any other circumstance.

I could be missing something here, in which case I’ll need to change a couple methods on `Vector{MyType}` which I’ve defined while assuming that this isn’t piratical. So this is more of a motivated question than a definitive statement.

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [February 26, 2024, 4:27pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797/4 "2024-02-26T16:27:53Z")

</div>

> [@mnemnion](#):
>
> But `notmymethod(t::NotMyType{MyType})` can’t affect code you don’t own,

I tried to show in my example above that the owner of `notmymethod` and `NotMyType` might expect the call to have undocumented side effects. I think it’s quite reasonable if it’s all internal like in that example. So in this case type piracy is causing problems because of ways it _doesn’t affect_ the code it doesn’t own…

---

<div class="post-metadata">

**Author:** ![sadish-d](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sadish-d/32/48058_2.png) [@sadish-d](https://discourse.julialang.org/u/sadish-d)\
**Post date:** [February 26, 2024, 4:33pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797/5 "2024-02-26T16:33:36Z")

</div>

So looks like we need to have two actors to talk about piracy: “I” and “others”. So the question is, is Julia also “others”? I think yes, right? Because if I overwrite, say, `propertynames(::Type{MyType})` and get rid of `:name`, it does break things for Julia, even though it only affects code I own. That’s how I’m making sense of it anyway.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [February 26, 2024, 4:34pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797/6 "2024-02-26T16:34:04Z")

</div>

> [@sijo](#):
>
> So it makes sense to me that users are not allowed to define `get_a(s::S{CustomType})` even if they own `CustomType`.

AFAIK, the concept of type piracy does not involve whether names are public or internal. Defining my custom method `myfoo(::NotMyPackage.InternalType)` is not type piracy. However it is not good general practice because minor revisions to `NotMyPackage` can break or remove `InternalType`, so I’d have to fix my own code every time that happens. If that code is a package, I’d have to make strict `[compat]` and couple my own package revisions to `NotMyPackage`.

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [February 26, 2024, 4:44pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797/7 "2024-02-26T16:44:19Z")

</div>

I agree. But one of the ways in which type piracy can cause problems, is by interfering with the internal working of a package, like in my example. By breaking the assumptions made internally by the authors.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [February 26, 2024, 4:47pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797/8 "2024-02-26T16:47:36Z")

</div>

Piracy is pretty straightforward and has nothing to do with internals.

It’s all about the fact that method tables are a shared global resource. The package that defines the function can define its methods with _any types it wants_, from any part of the ecosystem. It’s defining the standard behaviors.

Other packages should only extend that function with _types they own_ in accordance with the function’s expectations.

It’s the **both** situation that’s the problem: when you’re adding methods to a function you don’t own with types you don’t own. That’s piracy. [Style Guide · The Julia Language](https://docs.julialang.org/en/v1/manual/style-guide/#Avoid-type-piracy)

Of course, you can also just implement broken definitions that _aren’t_ pirating that’ll crash internals because they’re plain old buggy.

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [February 26, 2024, 4:50pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797/9 "2024-02-26T16:50:29Z")

</div>

I think we all agree on that, the discussion here is about what qualifies as “types you own”. In particular, does `NotMyType{MyType}` qualify or not…

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [February 26, 2024, 4:53pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797/10 "2024-02-26T16:53:43Z")

</div>

> [@sijo](#):
>
> In particular, does `NotMyType{MyType}` qualify or not…

I don’t think extending a method with `::NotMyType{MyType}` would be considered piracy in and of itself, no, but it’s probably a good idea to ensure that `NotMyType` expects its parameters to be depended upon in this manner. Often those are the sorts of situations where you need to be very careful about ensuring such a definition isn’t plain broken (or overly fragile).

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [February 26, 2024, 4:56pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797/11 "2024-02-26T16:56:56Z")

</div>

> [@Unsure about properties](https://discourse.julialang.org/t/unsure-about-properties/110756/18):
>
> But one of the ways in which type piracy can cause problems, is by interfering with the internal working of a package

I agree that messing with internals is brittle, I’m saying that is a separate bad practice from type piracy.

> [@Unsure about properties](https://discourse.julialang.org/t/unsure-about-properties/110756/20):
>
> does `NotMyType{MyType}` qualify

It does get weird to say it’s a type you “own” because it’s a `NotMyType` subtype and, strictly speaking, depends on names defined in multiple places, but yes you can claim ownership because the explicit `MyType` parameter isolates the method from any possible call signature lacking `MyType`. Sure we’ll be adding to a method table we didn’t create in `notmyfoo(x::NotMyType{MyType})`, but it would be a novel branch you have full developer control over. For example, `notmyfoo(x::Ref{S})` and `notmyfoo(x::S)` are both not type piracy, though you should adhere to how `notmyfoo` treats `Ref`s in general.

I think it’s important not to overfocus on method tables, or rather one should also consider what’s _not_ in a method table. As disastrous as it is to insert a method into the middle of a method table and change another package’s method dispatch design, it is also disastrous to add methods that shouldn’t exist to a method table. `*(::Symbol, ::Symbol)` is all concrete types so it seems like a trivially novel branch that couldn’t usurp any existing method, but all the types belong to `Base` so that’s the only place you can have full control as a developer. For example, you can’t do anything about another `Base` method relying on the `*(::Symbol, ::Symbol)` call signature to lack any method.

> [@sijo](#):
>
> Of course it’s fine if I document that it’s allowed (as in the `convert` case).

Under no circumstance should type piracy be documented as allowed, and `convert` isn’t doing that.

Should this be split to a “Is `notmyfoo(x::NotMyType{MyType})` type piracy” topic? It’s an important aspect of implementing custom properties but seems to be more of an independent tangent.

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [February 26, 2024, 5:25pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797/12 "2024-02-26T17:25:52Z")

</div>

> [@mbauman](#):
>
> I don’t think extending a method with `::NotMyType{MyType}` would be considered piracy in and of itself, no, but it’s probably a good idea to ensure that `NotMyType` expects its parameters to be depended upon in this manner. Often those are the sorts of situations where you need to be very careful about ensuring such a definition isn’t plain broken (or overly fragile).

Taking a close look at the style guide, there’s a separate guideline [don’t overload methods of base container types](https://docs.julialang.org/en/v1/manual/style-guide/#Don't-overload-methods-of-base-container-types), which surely applies to doing weird things to `getproperties(::Type{MyType})`.

And I actually don’t follow that guideline religiously in my own code, and probably should. The type itself isn’t exported, but instances of it can end up in user code, and even though there’s no good reason for them to put those structs into a Vector, it would in fact do weird things were they to do so.

It’s kind of a pain in the butt to wrap a Vector in a struct and supply all the necessary methods for it, having been down that road I frequently find myself doing some Vector business which I didn’t account for, getting an error, and having to shift focus back to the type in question to implement the missing method. But I do see why taking the lazy route falls short of best practice.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [February 26, 2024, 5:54pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797/13 "2024-02-26T17:54:40Z")

</div>

> [@mnemnion](#):
>
> surely applies to doing weird things to `getproperties(::Type{MyType})`

No, because `Type` is not a container.

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [February 26, 2024, 6:00pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797/14 "2024-02-26T18:00:02Z")

</div>

> [@Benny](#):
>
> No, because `Type` is not a container.

“The trouble is that users will expect a well-known type like `::Type` to behave in a certain way, and overly customizing its behavior can make it harder to work with.” To paraphrase the guide.

Perhaps this could be updated to read “Don’t overload methods of base parametric types”, that would nicely avoid this sort of quibble, because it’s clear that the same logic applies to all of them.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [February 26, 2024, 6:02pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797/15 "2024-02-26T18:02:00Z")

</div>

> [@mnemnion](#):
>
> “The trouble is that users will expect a well-known type like `::Type` to behave in a certain way, and overly customizing its behavior can make it harder to work with.” To paraphrase the guide.

Again, `Type` is not a container type, so this is invalid paraphrasing of “The trouble is that users will expect a well-known type like `Vector()` to behave in a certain way”. [Parametric type](https://docs.julialang.org/en/v1/manual/types/#Parametric-Types) is not synonymous with [container type](https://en.wikipedia.org/wiki/Container_(abstract_data_type)).

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [February 26, 2024, 6:04pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797/16 "2024-02-26T18:04:07Z")

</div>

> [@Benny](#):
>
> Again, `Type` is not a container type, so this is invalid paraphrasing of “The trouble is that users will expect a well-known type like `Vector()` to behave in a certain way”. Parametric type is not synonymous with container type.

Again, the manual should be updated to prevent this kind of pointless rules-lawyering, because, in fact, the same logic applies to any Base parameter type.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [February 26, 2024, 6:06pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797/17 "2024-02-26T18:06:19Z")

</div>

The manual is already very clear about the principle applying only to container types in `Base`, and no further rewording can prevent misreadings and mistaken extrapolations.

---

<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:** [February 26, 2024, 6:24pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797/18 "2024-02-26T18:24:16Z")

</div>

@mnemnion The `::Type{MyType}` case is a bit special. It’s kind of a special construct (called a “type selector”) that is mainly included in the language so that you can dispatch on a type object. To [quote from the manual](https://docs.julialang.org/en/v1/manual/types/#man-typet-type):

> While `Type` is part of Julia’s type hierarchy like any other abstract parametric type, it is not commonly used outside method signatures except in some special cases.

Thus, it is perfectly normal to write a method like this:

```julia
Base.parse(::Type{MyType}, s::AbstractString)

```

(EDIT: But I do wonder if overloading `getproperty` and `setproperty!` on `Type{MyType}` would have weird consequences.)

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [February 26, 2024, 6:57pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797/19 "2024-02-26T18:57:58Z")

</div>

> [@CameronBieganek](#):
>
> Thus, it is perfectly normal to write a method like this:
> 
> `Base.parse(::Type{MyType}, s::AbstractString)`

Which is fine, because `Base.parse(::Type{T}, ...) where {T}` isn’t defined. It isn’t an overload of a base method on a base parametric type, so this wouldn’t be a problem for Vector either: defining `method(::Vector{MyType}...)` for a method which Base doesn’t define for Vector should be fine by the same logic.

I wouldn’t expect good results from a custom implementation of `reinterpret`, however. That would deviate from expected behavior, in the same way which the style guide recommends against.

I don’t see reasons why container types would work different from other parametric types this way. In either case one would want generic code using Base methods to work correctly for all concrete variants.

---

<div class="post-metadata">

**Author:** ![sadish-d](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sadish-d/32/48058_2.png) [@sadish-d](https://discourse.julialang.org/u/sadish-d)\
**Post date:** [February 26, 2024, 7:04pm UTC](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797/20 "2024-02-26T19:04:21Z")

</div>

Consider this situation:

Author A writes:

```julia
struct NotMyType{T} end
obscure_function(::NotMyType) = true
is_NotMyType(t::NotMyType) = obscure_function(t)

```

Using Author A’s package, Author B writes:

```julia
struct MyType end
obscure_function(::NotMyType{MyType}) = nothing # bad, but is it piracy?

is_NotMyType(NotMyType{Bool}()) # true
is_NotMyType(NotMyType{MyType}()) # nothing

```

Author A has made certain assumptions when implementing `is_NotMyType` that are completely valid under their context, but Author B’s redefinition of `obscure_function` breaks it.

Is there another word for the bad thing that Author B did if not type piracy?

[Next page](https://discourse.julialang.org/t/is-dispatch-on-another-types-parameter-notmytype-mytype-piracy/110797.md?page=2)
