3 ms·
No, the compiler doesn't infer the types quite like you're imagining. It is possible, depending on usage, to have TI(1) of type T<~str>, or TS(~"Hello") of type
by andolanra 13y ago
No, the compiler doesn't infer the types quite like you're imagining. It is possible, depending on usage, to have TI(1) of type T<~str>, or TS(~"Hello") of type T<int>. The following is actually still legal in the first example, and will result in a runtime error:
let a = TI(1);
let b = TS(~"foo");
let z = concat(a, b);
The reason is that the Rust compiler is trying to work out the types for you. In this case, it sees that concat requires two T<~str>s and infers logically that both a and b must have the type T<~str>... even though one of them was created with TI.
If you look at the example with a compile error, you'll notice that the two things being concatenated which result in the error were themselves the results of calls to `plus` and `concatenate`, which are guaranteed to produce T<int> and T<~string>. You could also guide the compiler by providing the types manually
let a : T<int> = TI(1);
let b : T<~str> = TS(~"foo");
/* now this produces a compile-time error */
let z = concat(a, b);
Or by writing wrapper functions over the constructors
fn makeTI(i : int) -> T<int> { TI(i) }
fn makeTS(s : ~str) -> T<~str> { TS(s) }
...
let a = makeTI(1);
let b = makeTS(~"foo");
/* this also now produces a compile-time error */
let z = concat(a, b);
Other languages with phantom types use something called Generalized Algebraic Data types (GADTs) which—to handwave a bit—are something like the latter solution, except built directly into the data type constructors (rather than manually writing those extra functions).