Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to do a compile time type check on a generic in Rust?

Tags:

types

rust

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.

like image 685
Daniel Fraenkel Avatar asked Dec 24 '16 10:12

Daniel Fraenkel


People also ask

Do rust traits support generics?

Rust supports polymorphism with two related features: traits and generics.

How do rust generics work?

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.


1 Answers

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:

Runtime checks

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.

Introducing a custom trait

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.

A real solution: dependent types

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).

Thoughts on compile-time checks

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.

like image 96
aochagavia Avatar answered Oct 19 '22 02:10

aochagavia