Specify type of identites in pattern bindings


#1

This would be [pre-rfc], but at present I have no idea how to correctly write an RFC, so instead I’ll just start a discussion

At present in rust, it is not possible to specify the type expected as the result of a pattern binding. This means we can’t take advantage of things like dynamic dispatch in match branches (I see dynamic dispatch of pattern bindings as the main feature of this).

The actual code that caused me to want to start a discussion of this, is as follows

match self {
    &Logogram::UniMonoGram(ref a) | &Logogram::DiLogogram(ref a) => f.fmt(a),
    &Logogram::DuoMonoGram(ref a, ref b) => write!(f, "({}{})", a, b),
}

both a under UniMonoGram which has type MonoLogogram and a under DiLogogram which has type DiLogogram implement std::fmt::Display, but there is no way for me to instruct Rust to do dynamic dispatch here at present. In fact, it is not possible to specify the type of the two a’s at all (unless I am mistaken)

I’d propose allowing the usage of a where clause on pattern bindings, allowing you do something like this

match self {
    &Logogram::UniMonoGram(ref a) where a: &Display | &Logogram::DiLogogram(ref a) where a: &Display => f.fmt(a),
    &Logogram::DuoMonoGram(ref a, ref b) => write!(f, "({}{})", a, b),
}

another more minimal example of this is at present you cannot specify the types of the integers in a sequence like

let (x, y) = (12, 42);

obviously in this case this is not a problem, because you can just specify the type on the literals, but I digress

let (x, y) where x: i32, y: i32 = (12, 42);

As a note based on what myself and @durka discussed on IRC, this may seem to have some conflict with the fact you can do let ref x: i32 = 12; but not let ref x: Display = 12;. I’m no expert on how ref is implemented, but I’d suggest that using where clause on pattern bindings should run after all bindings (including ref) are complete, so the aforementioned would look like let ref x where x: &Display = 12


#2

let (x, y): (u8, u16) = (8, 16); is valid rust, so I’m not sure that your minimal example is representative of the problem.


#3

ah. let (ref x, ref y): (&u8, &u16) = (8, 16) is not though, which would be let (ref x, ref y) where x: &u8, y: &u16 = (8, 16)


#4

I proposed something similar to this as part of the type ascription RFC. It was removed because we didn’t think it was high enough priority to work on immediately. I would like to see it added to the language eventually. RFC issue.


#5

So the reason that’s not valid Rust is that this is valid Rust:

let (ref x, ref y): (u8, u8) = (0, 1);

The ref isn’t part of the type of the pattern, its more like something that’s applied to the binding that’s created out of the pattern (similar, really to mut).

It seems like what you want is to be able to ‘cast’ the binding more than specify it. ref could be thought of an operator that casts the binding to a reference; you want to be able to cast it to, if not any type, at least to a trait object.

I would see a syntax like this making sense for that purpose.

let x as &Display = &0;
let ref x as &Display = 0;

These are the same as let x = &0 as &Display, but obviously in a match this becomes tricker to do.

This feature makes sense to me, not sure if there are any caveats I don’t see other than general complexity concerns.