Enum variants with common functionality, avoiding boilerplate


#1

I’m messing around with a practice project and I’m wondering if there’s a way to succinctly express this code… I’ve got an enum that represents all of the datatypes in SQL Server:

#[derive(PartialEq)]
pub enum SqlType{
    Numeric { scale: u16, precision: u16 },
    Bit,
    TinyInt,
    SmallInt,
    Int,
    BigInt,
    SmallMoney,
    Money,
    Float,
    //a whole bunch of other stuff
}

Now, I’d like to be able to write a function on SqlType that is called like so:

enum TypeConversionDetail{
    Implicit,
    Explicit,
    ImplicitWithLoss,
    ExplicitWithLoss,
    NotAllowed
}

impl SqlType{
    fn get_conversion_details_for(&self, other: SqlType) -> TypeConversionDetail{
         //VERY large match statement, n*n in size (roughly) where n is # of types
    }
}

How can I encapsulate this? I’d like to be able to write this a chunk at a time (e.g., write a get_conversion_details_for for each type like so:

impl SqlType::Numeric {
    fn get_conversion_details_for(&self, other: SqlType) -> TypeConversionDetail{
         //smaller match statement!
    }
}

However, this isn’t possible. In addition, manually changing the enum to contain real types still forces you to write the original match statement that delegates the conversion logic to each type.

Is there a better way to do this?


#2

Your example of how you want to write it has actually been proposed in an rfc; it’s probably years away from being added to the language, if at all, though.

In the mean time, depending how complicated the code is each pair is, you may be able to use a macro to more easily generate all the matches. For example I had a similar N^2 issue matching code licenses, but because the result was a simple bool I was able to use a macro to avoid writing the matches in full.


#3

One large match is the way to go. It is not all that bad. E.g. all relevant code for this is found in one place, so you always know where to look, and it is immediately visible what happens:
(Int, BigInt) =>Implicit,
It will be like a lookup table, which is not a bad concept at all.


#4

The best representation might actually be a two-dimensional lookup table:
Rows - what to convert
Columns - conversion target
Cell - type of conversion
I’m sure this format could be achieved in the source code with some macro magic, but it’s probably not worth it…