How do you think using `as` to provide type inference hint?

Though type inference is great in Rust, sometimes we still need explicit type annotation.

// Ideal, but doesn't work due to lack of collection type information.
let a = [1,2,3].iter().collect();

// Works, but suboptimal as we need to put type annotation.
let b: Vec<&i32> = [1,2,3].iter().collect();

If we cannot eliminate the type annotation,
how do you think about moving type annotation to the end with as keyword?

// Optimal IMO. 
// Provide collection type information with `as` keyword.
let c = [1,2,3].iter().collect() as Vec<&i32>;

Swift supports this kind of inference in limited context and this makes code more readable IMO.

It sounds like you're talking about Type Ascription.

It's an unstable feature that's been around for a while, although I'm not sure how keen people are on the idea. 99% of people would just write the type annotation as let c: Vec<_> = ... so I feel like adding a third way to specify types (normal type annotations and turbofish .collect::<Vec<_>>()) would be a bit redundant.

7 Likes

Yes that is what I am talking about. Thanks for reference.

I don't agree with you on 99% people would prefer explicit type annotation like let a:Vec<_> = .... Because I think type annotation makes significant noise in code reading. Therefore I think it would be better moving it to the end of the statement at least rather than first or second place of the statement.

If people don't like type-ascription, I think it could be due to its syntax. : looks less readable than as to me. Just my opinion for the record.

Using as is pretty weird, as it's normally used for conversion, but there's no conversion here. Why not use the turbofish?

3 Likes

In my experience, programmers tend to be split into 4 camps:

  1. Those who like static typing, and prefer explicit type annotations
  2. Those who like static typing but prefer no type annotations, requiring type inference (which is impossible to do with the .collect() method above)
  3. A mixture of 1 and 2 (I tend to elide types only for super-obvious local bindings, and for unnameable types like closures. I prefer type annotations though because in most places what you call noise, I call documentation)
  4. Those who prefer unityped/untyped systems (e.g. Python, Javascript, Ruby etc). Why this group is around I'm not completely sure, since the lack of static typing mostly only means you need to write way more tests i.e. it only means more work for the programmer(s)
    (It also means the availability of e.g. heterogeneous containers like [1, '2'] but that's never seemed compelling enough to forego static typing)

IMO you feel it weird because you want to limit as as strictly conversion only. I am suggesting to expand as can be used for type-ascription operator instead of :.

I think as keyword is very good to expression programmer's intention for specific final result type from incomplete generic type. It looks like saying "I want this Vec<_> as Vec<usize>". : is okay, but I just want to clarify my opinion for the record.

I am not sure what you mean "using turbofish". Can you explain me some more?

Using the turbofish operator looks like this, and allows you to put the type at the end:

let c = [1,2,3].iter().collect::<Vec<&i32>>();

playground

1 Like

Turbofishing unfortunately only helps if you have a generic function. It doesn't help when you need to assist deduction for intermediary expressions that are not generic.

I find myself having to occasionally assign to a variable of a particular type just to be able to have a concrete enough type for the rest of the expressions to be unambigious.

Type ascription would help then I guess, but I like targeting stable :frowning:

1 Like

I didn't know this syntax can also be used on functions. Thanks!

I think I am in camp #3. And I think we are actually in same camp.

IMO basically,

  • Callable interfaces and memory layout declarations (e.g. trait signature, function signature, struct/enum) are documentation and better with full type annotations.
  • Hidden implementation details (e.g. local bindings) are not documentation and doesn't need full type annotations. It would be better to elide them if it's possible losslessly.

I think "noise" was a poor choice of word. Actually I am a huge fan of static checks and type-dependent programmer. It's too painful writing code without type checks.

1 Like