That’s as expected and still not type-piracy. You just defined a type r2 that doesn’t work correctly, so anyone who uses the r2 from that package will get incorrect results. This doesn’t have to do with package interactions, it’s just the definition and overrides of r2 that are the issue. If other developers avoid your package because they know your r2 is incorrect, then it will not affect their code and they are fine.
I think you’re not understanding what is nefarious about the actual type piracy case. The cases you’re talking about is whether someone should be allowed to use your type in their functions. Should I be allowed to use PackageA’s definition of a Number in the differential equation solvers? Yes, there’s no issue with the extension, and as long as you don’t choose to use PackageA’s number type you aren’t effected. As long as the differential equation solver doesn’t choose to use PackageANumber, having PackageA in scope won’t even do anything.
The actual type piracy case is different. If PackageA defines
Base.:*(a::Float64,b::Float64) = PackageANumber(a*b)
then any time PackageA is in scope, it takes over any code that uses multiplication. You can’t choose to opt in or out of it by choosing what types and functions you’re using: the existence of PackageA will modify the standard way that * works. It also infects everything. If PackageB uses PackageA, then because Base will have changed, using PackageB will change how your code in the REPL works, even if nothing is exported from both PackageA and PackageB.
Another way of saying it is this. The useful definition of type piracy, the one that says you can only extend functions on your own types, means that if PackageA is a type-pirate, adding using PackageA to the module file of PackageB (and doing nothing else) cannot break PackageA’s code. If PackageC is a type-pirate, just adding using PackageC and doing nothing else can break PackageB’s code (that’s without calling any functions or building any types from PackageA). PackageA is safe because it only hurts if you use its extended functionality, PackageC is causes unpredictable changes to any code with which it is in scope (actually, redefining functions in Base from PackageC will break scripts in Main even if PackageC is in scope of PackageA without being exported… gah!). This is why the definition is the way it is.