normal C: the programmer will write what type they want, easy
C++: we're fancy, the compiler can, like, infer type stuff on the left side of an assignment based on the type on the right side! it might make it a little harder to figure out stuff like iterator types without a fancy IDE but it will be worth the convenience if the feature isn't overused
Rust: you're like a baby, hold my beer, we will infer part of the type of a variable based on WHAT HAPPENS DOZENS OF STATEMENTS FURTHER DOWN mwahaHAHAHAHAHA good luck trying to read this code in one pass suckers
in rust it is apparently normal that you can create a vector, call functions on it that resize it and whatnot, and then later insert elements, and the element insertion implicitly provides the type and element size needed to compile preceding method calls
@siguza I'm not fluent enough in rust to understand any of what's going on there
@jann neither am I, but apparently it's a soundness bug in the Rust compiler (or the specitself?), first reported over 10 years ago, and still unsolved as of today :) https://github.com/rust-lang/rust/issues/25860
Implied bounds on nested references + variance = soundness hole · Issue #25860 · rust-lang/rust

The combination of variance and implied bounds for nested references opens a hole in the current type system: static UNIT: &'static &'static () = &&(); fn foo<'a, 'b, T>(_: &'a &'b (), v: &'b T) ->...

GitHub

@siguza @jann a good explanation of cve-rs involving cat souls

https://youtu.be/vfMpIsJwpjU

Safe Rust AIN'T SAFE!? (cve-rs)

YouTube

@Logical_Error @jann hmmm... I guess I don't understand enough Rust, because it's entirely not clear to me why &'static &'static counts as &'b &'a when the variable passed in as &'a does not have static lifetime.

I get the concept of "seeing this type is proof that one type outlives the other", it's just that in this case, the type passed in seems entirely unrelated to the lifetime of the variables involved...

@siguza @jann

maybe someone in #rustlang can explain cve-rs another way?

im not too familiar with rust myself so i dont want to lead u down the wrong direction, but &’static can be used in place of &’a because &’static (which lasts forever) is guaranteed to last &’a (which lasts within that forever)

the video explains that this is because of contravariance: https://en.wikipedia.org/wiki/Type_variance#Contravariant_method_parameter_type

i definitely had to watch the vid a couple of times to understand it 😅

Type variance - Wikipedia

@Logical_Error @siguza @jann I think your explanation is correct.

BTW, I had a university PL course covering covariant and contravariant, and I think most of my peers at that time failed to understand it. The complexity is why most languages don't let programmers control that and instead implement a limited, hard-coded form (e.g. OOP languages' pointer-to-derive-class to pointer-to-base-class implicit conversion), and Rust lifetime.

@lesley @Logical_Error @jann I mean, it's kinda the same issue as array types. Given an inheritance chain Grandparent -> Parent -> Child, Array<Parent> can be cast neither to Array<Child> (because you can get elements out of it that are not of type Child) nor to Array<Grandparent> (because if you put a Grandparent into it, then you can now get things out of it that are not of type Parent).

So I feel like the "witness type" should only work for an exact match of lifetimes, otherwise stuff breaks...