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 There was a lot of work done around generics and lifetime parameters, including language changes, and I'd venture to say there is still willingness to solve it.
Fix unsound lifetime extension in HRTB function pointer coercion · kstrafe/rust@7f689bf

Fixes #25860 = Problem = The compiler allowed unsound coercions from function items/pointers with nested reference parameters to HRTB function pointers, enabling arbitrary lifetime extension to &...

GitHub

@burakemir @jann and where does this commit... live? GH tells me:

This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

(Your link is for kstrafe/rust, but same goes for rust-lang/rust.)

@siguza @jann Here is the discussion https://github.com/rust-lang/rust/pull/147543 apparently not a full fix. But... evidence of willingness to fix 😉
cve-rs: Fix unsound lifetime extension in HRTB function pointer coercion by kstrafe · Pull Request #147543 · rust-lang/rust

Doesn't fix but slightly patches #25860 = Problem = The compiler allowed unsound coercions from function items/pointers with nested reference parameters to HRTB function pointers, enabling arbi...

GitHub

@burakemir @jann oh yeah, I assumed there was willingness to fix.

I just said it scares me because this feel like the kind of issue that requires you to potentially invent new math...

@siguza @jann Yeah, I understand the concern. The cve-rs unsoundness is not due to the type system unsoundness (the math being wrong) but due to the implementation not checking enough. This is addressed by the new trait solver, which is a declarative model (chalk, logic programming with hereditary Harrop formulas) and its implementation, which has taken years and should land this year. So the math is already there, the implementation is almost there. That is what I meant by willingness to fix, the fix is actually work in progress.

@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...

@jann is that bad? Never bothered me.

What actually mattered for me in practice was the absence of implicit conversions

@kitkat @jann it is not bad, it is surprising when used to the relatively vague typing of C/C++
@jann Automatic type deduction and conversion, so great when they work, and so painful when they do not! An @ACCU _CVu_ journal article recently spot-lighted how weird C++ implicit type conversions can be. Somehow I find remembering which types are trivially constructible from one another difficult.