Is there any historical reason why rust has both :: turbo fish and . Dot notation? Why not just stick with the one like in python in other languages?

This question may sound a little immature but I have only working experience with python programming and I would like to ask why rust developers choose to keep turbofish and dot operators to access methods in language?

Please do direct me to the sources if there are subtle differences between these two rotations, I would like to learn more. Thank you so much

1 Like

The :: notation is used to specify the path to something. This might be a module, a constant, a function, a struct and some other options as well.

The dot notation calls a method on a value or accesses a field on a value.

The difference is that one is used to access free-standing things, and the other does things to a value.

2 Likes

To add on to this, Python has very little distinction between compile-time and run-time. Classes and modules can be modified during program runtime, and thus "accessing a function in a module" is a very similar operation to "accessing a value of an object". Classes in python are values themselves, and thus getting a function of a class is similar to calling a method on an instance of that class.

In contrast, rust is pre-compiled and has a much stricter difference between things that can be accessed at compile time, and things that are using runtime data to retrieve. :: always refers to finding something that is known at compile time, like a type, or a function, or a module. . on the other hand accessing things from some value that only exists at runtime. MyStruct::my_func() uses :: because the "value" MyStruct::my_func is a function which is defined and known at compile time. let x = MyStruct::new(); x.my_method(); uses . because x is a value here (not a type), and calling my_method will require passing in x's self at runtime.

This explanation isn't entirely accurate, as we still use . to access fields of constant values, and those are then also constants. It's more the difference between "types / namespaces" and "values" than between compile-time-known-things and runtime-known-things. But since types and namespaces are always known at compile time, I think it's a useful enough analogy.

6 Likes

I'm not a specialist in Rust nor I know the exact rational for this syntax, but I like to think it like this:

:: is for types and . is for values. Just like in functions, < > is for type parameters and ( ) is for value parameters. Rust likes to keep those two contexts separate.

Besides, the :: has other uses, also connected to types.

  1. It can disambiguate when a method exists in multiple traits. For example, the I type is an iterator and also implements my trait Linked. We must tell the compiler which next we want to use every time.

    trait Linked {
        fn next(&self) -> Self;
    }
    
    fn my_func<T, I: Iterator<Item=T> + Linked>(mut values: I) {
        let next_value = Iterator::next(&mut values).unwrap();
        let next_iterator = Linked::next(&values);
        // next_value: T and next_iterator: I
    }
    
  2. The :: is used in the "turbo-fish" syntax, to tell the compiler which type parameter to use (either because you want to be explicit about it or because it's needed.

    fn my_func() {
        let not_fine = "17".parse().unwrap(); // which type are you parsing to?
        let compiles: i32 = "17".parse().unwrap();
        let also_compiles = "17".parse::<i32>().unwrap();
        let compiles_but_not_needed: i32 = "17".parse::<i32>().unwrap();
    
        use std::collections::HashSet;
        let total_unique: u64 = vec![1, 2, 3, 2].into_iter().collect::<HashSet<u64>>().into_iter().sum();
    }
    

    How would the compiler know we wanted to construct a HashSet to keep only the unique values?

I'm not sure, but from your initial question it seems like you may be confusing the turbofish ::< > with the more general :: syntax. I don't know if Rust has a documented name for :: though.

4 Likes

I've found the change in git, but it doesn't reference any discussion about it:

https://github.com/rust-lang/rust/commit/3816e57fd2a8ab19e4ac6d4b3ddd5b49d5973ff2

https://github.com/rust-lang/rust/commit/6510f1ce7cb026ceb98689583c13f18c1e7c2c12

5 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.