I don't want to check whether a type has a certain trait but I would like to be able to differentiate between, e.g. a struct and an integer. Since both a struct and an integer can implement the same trait, I don't know how I could tell them apart.
The reason that I want to do this is because I am using serde_json to convert a generic type to JSON but I only want it to become a JSON Object
(which happens when it is a struct) but it should not convert to anything else (like an JSON I64
). Since both structs and integers can implement the Serialize
trait, there is no way to tell them apart.
Currently, I let the process panic because it is not an error it could recover from, but since I could potentially know this at compile time, I am wondering whether there is any mechanism to determine the type at the compile stage.
I would like to know how I can tell types apart by their "kind" and not by their traits.
Rust supports polymorphism with two related features: traits and generics.
When defining a function that uses generics, we place the generics in the signature of the function where we would usually specify the data types of the parameters and return value. Doing so makes our code more flexible and provides more functionality to callers of our function while preventing code duplication.
Even if you managed to compare the types at compile time, nothing prevents a struct
from being serialized as a Json::I64
. Its Serialize
implementation could be anything! I can think of some partial solutions:
Add a runtime check to see if the result is indeed a Json::Object
by pattern matching. You could combine this with an assertion in case you expect this to be always true. I think this is what you are doing now.
It would be possible to create a new trait:
trait SerializeAsObject : Serialize {}
Which you would then implement only for those data types you are sure will be serialized as objects. However, nothing prevents you from implementing the trait for i64
, so there is still room for error here.
You would probably need a type system supporting dependent types in order to ensure that serialization of a data type always results in a given kind of output. As far as I know, such a type system is so complex that there are no widely used languages out there supporting it (you could take a look at Idris in case you want to know more about this).
While it is great to have compile-time checks, the compiler can only go so far. In my experience, using dependent types in real world programming is not worth the hassle. For instance, in this case, you would need to provide a mathematical proof so the compiler can understand that the implementation of Serialize
always results in serialization of an object.
Even then, there is no way to ensure a program is bug free! Therefore I think in this case the right thing to do would be to use an assertion, document that your function will panic in case the data cannot be serialized as an object, and write unit tests to ensure it is called correctly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With