Even more clarification on Type piracy

Clarification: if I don’t export a “pirated” function/type, is that ok? An example: I’m building a package to do stuff with temperature, and using Unitful all over the place. But I want to give users the option of just calling all of the functions that take temperatures with numbers instead.

Can I do:

import Base.convert
convert(::Type{Temperature}, x::Real) = # something that turns it into temperature

(Note: Temperature isn’t actually the real type, but I’m on mobile so forgive me please)

I know I could explicitly define extra methods that take numbers as arguments, but that seems needlessly verbose. If I don’t re-export convert, it won’t actually contaminate other people’s code right?

1 Like

No it’s not. See my example above for how this still (secretly) effects other codes.

Base.convert is a single function. As long as one library (Base) reexports it, it exists out there in the wild. You mutated it by adding a method. The one out there in the REPL is now mutated. That’s why type-piracy is so bad.

I might call

Base.:*(a::Float64,b::Float64) = PackageANumber(a*b)

method piracy. You have not extended a function you don’t own on types that you don’t own. Rather you’ve overwritten an existing method in Base. (or at least stolen an existing dispatch). You have commandeered something that is already in use. It’s obviously a semi-insane thing to do if you expect anyone else to use your package.

On the other hand, for one of the scenarios mentioned above, I prefer a term that Tony Kelman used: type squatting. It’s more evocative of the problem. For instance:

julia> :x * :y
ERROR: MethodError: no method matching *(::Symbol, ::Symbol)
Closest candidates are:
  *(::Any, ::Any, ::Any, ::Any...) at operators.jl:424

julia> Base.:*(a::Symbol,b::Symbol) = :($a * $b)

julia> :x * :y
:(x * y)

If the package containing this code becomes widely used, then I’ve prevented julia, ie Base and the standard library, from extending its own function on its own types. I’m occupying something that was not being used. And evicting me could be difficult when that something needs to be used.

But, type squatting also causes an immediate problem with existing code. Namely, it may prevent an exception from being thrown as soon as possible after a function receives unsupported input data.

2 Likes

Huh… I thought you had to explicitly re-export the function to put the new method into scope when someone does using… Good to know.

Here is an example of not re-exporting.

julia> module A
         export c
         *(a,b) = 4
         c = 3 * 3
       end
Main.A

julia> using Main.A

julia> c
4

julia> 3 * 3
9

Without the Base., the overwriting does not propagate