Enum field types (datasort refinements)


#1

I’ve seen this old article (that contains obsolete types and syntax) about phantom types:
https://bluishcoder.co.nz/2013/08/15/phantom_types_in_rust.html

So I’ve tried to update and improve the code ( https://bluishcoder.co.nz/rust/pt/test2.rs ) like this:

mod tis {
    use std::marker::PhantomData;
    use std::fmt;

    pub enum T<A> {
        Ti(i32, PhantomData<A>),
        Ts(String, PhantomData<A>),
    }

    pub type Ti32 = T<i32>;
    pub type TString = T<String>;

    impl T<i32> {
        pub fn new(i: i32) -> Self { T::Ti(i, PhantomData::<i32>) }

        pub fn plus(self, b: T<i32>) -> Self {
            if let (T::Ti(i1, _), T::Ti(i2, _)) = (self, b) {
                return Ti32::new(i1 + i2);
            }
            panic!();
        }
    }

    impl T<String> {
        pub fn new(s: String) -> Self { T::Ts(s, PhantomData::<String>) }

        pub fn concat(self, b: T<String>) -> Self {
            if let (T::Ts(s1, _), T::Ts(s2, _)) = (self, b) {
                return TString::new(s1 + &s2);
            }
            panic!();
        }
    }

    impl<U> fmt::Debug for T<U> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            match self {
                &T::Ti(i, _) => write!(f, "i32: {}", i),
                &T::Ts(ref s, _) => write!(f, "str: {}", s),
            }
        }
    }
}

fn main() {
    use tis::*;

    let d1 = Ti32::new(1);
    let d2 = Ti32::new(2);
    let x = d1.plus(d2);
    println!("{:?}", x);

    let d1 = TString::new("Hello, ".into());
    let d2 = TString::new("World".into());
    let y = d1.concat(d2);
    println!("{:?}", y);

    //let z = x.concat(y); // Compilation error.
}

(Inside the tis module the fmt() is not public, but the printf give no errors, do you know why?)

Several people have suggested to turn enum members into types ( https://github.com/rust-lang/rfcs/issues/754 ). If that happens in Rust then does it allow to rewrite that code like this?

use std::fmt;

enum T { Ti(i32), Ts(String) }

impl T::Ti {
    fn plus(self, b: T::Ti) -> Self {
        T::Ti(self.0 + b.0)
    }
}

impl T::Ts {
    fn concat(self, b: T::Ts) -> Self {
        T::Ts(self.0 + &b.0)
    }
}

impl fmt::Debug for T {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &T::Ti(i) => write!(f, "i32: {}", i),
            &T::Ts(ref s) => write!(f, "str: {}", s),
        }
    }
}

fn main() {
    let d1 = T::Ti(1);
    let d2 = T::Ti(2);
    let x = d1.plus(d2);
    println!("{:?}", x);

    let d1 = T::Ts("Hello, ".into());
    let d2 = T::Ts("World".into());
    let y = d1.concat(d2);
    println!("{:?}", y);

    //let z = x.concat(y); // Compilation error.
}

If this is right then it’s a significant improvement for the code.