Is this type piracy?

(::Type{T})(x::MyType) where T = dosomething(x) |> T

or perhaps just bad practice for some other reason?

This is basically hijacking all single argument constructors to first dosomething with MyType. This seemed like a convenient thing when I wrote it but now I’m having second thoughts.

In case context is needed, MyType is a TensorProto and dosomething is the method which figures out which field is used and reshapes and reinterprets it to the right shape and type. The above function gives the convenience that Array(readproto("file.pb", TensorProto())) and CuArray(readproto("file.pb", TensorProto())) just works.

I guess one drawback is that it could create a surprise for people who wants to wrap a TensorProto in some other struct, but if that is the only drawback I think it can be mitigated by just making T <: AbstractArray or just forcing people to overload for that type.

1 Like

It’s not type piracy, but it does cause a TON of method invalidations so it’s really bad for compiler latency.

And yes, you’re right that it’s likely a bad idea even if it’s not piracy and even if you don’t care about latency because it can lead to surprising and unexpected behaviour.

3 Likes

If dosomething returns a MyType, you’ll get a stackoverflow:

julia> struct MyType end

julia> dosomething(x) = x
dosomething (generic function with 1 method)

julia> (::Type{T})(x::MyType) where T = dosomething(x) |> T

julia> Int(MyType())
ERROR: StackOverflowError:
Stacktrace:
 [1] |>(::MyType, ::Type{T} where T) at ./operators.jl:834
 [2] Int64(::MyType) at ./REPL[4]:1
 ... (the last 2 lines are repeated 39988 more times)
1 Like

@Mason: Hehe, yeah. I haven’t learned to naturally think about invalidations yet, but I saw now that a late contender in the invalidation competition was more or less exactly this. Perhaps I can get a consolation prize for being the fool who actually put it in “real” code :slight_smile:

@Sukera: That’s of course true and kinda contributes to the overall shakiness.

2 Likes