Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

If you're wondering, "What is the turbofish?", it is the awkward syntax Rust requires when specifying generic arguments in an expression, such as:

  Vec::<u8>::new()



Am I the only one not really bothered by the turbofish? I just think 'declarations, no colons. expressions, colons.' and that rule generally works fine for me.


I love it. I'm not here to debate whether it should be there, but i like it nonetheless. Mostly because of the cute name.

And i came from being a Python "kill all syntax!" zealot back in the day, hah. Funny how in both Types and Syntax i have migrated from minimalist to explicitness over the years. I was such a zealot on both fronts in those Python days.


It's a straight-forward rule that (I think) I have mostly internalized. But coming from C++, I was initially mystified.


C++ has a rule similar to the turbofish though:

    #include <Eigen/Dense> // a library where I know it's required

    using namespace Eigen;

    int main() {
        VectorXd zeros = VectorXd::zeros(5);
        VectorXf zeros_float = zeros.template cast<float>();
        return 0;
    }


I'm sure you know better, but at first glance this seems wrong. Reason: `main` is not itself a template, so `cast` is not a dependent name.

C++ compilers used to be liberal about accepting unnecessary instances of the `typename` keyword so lots of people would just sprinkle them everywhere. Modern versions of both Clang and GCC call this out.

The actual rule: https://en.cppreference.com/w/cpp/language/dependent_name#Th...


You're right, since I'm frequently using templated functions I encounter this issue quite often, but here when I wanted to give an example I forgot I needed to be in a dependent context. I guess I'd better test my example next time I want to give one...


And I have never internalized it! This is me, but for `typename` and `template` in expressions: https://xkcd.com/1168/


The syntax gives me a warm feeling, reminding me in the moment that I'm not writing C++.


Specifically it's the ::<u8> part. It's only used when writing type parameters in an expression.

    let x: Vec<u8> = vec![]; // spelled Vec<u8> in "type context"
    let x = Vec::<u8>::new(); // spelled Vec::<u8> in "expression context"


Yes, and googling around for this rule is what landed me on this epic poem and test.


I find specifying type on the left side of assignment operator much easier to interpret.

> let x: Vec<u8> = Vec::new();


let x: Vec<u8> = vec![];


It’s also never clear where this appears, like a::<b>(c) or a::<b>::c()


in both case, `<b>` is a parameter of `a`, but in the former, `a` is a function with generic parameter and in the latter, `a` is a type with generic parameter.


The generic paramer is directly after the thing that has the parameter (it could be on the type or the method). With an exception, for enum variants it's after the variant, like None::<i32>


It makes me wonder. If things went differently, and if Rusty always needed this syntax for generic parameters, would the consistency have made the syntax more palatable?


As in, if declaring generics looked like `fn foo::<T>()` rather than `fn foo<T>`? I dunno, at think at that point you just stop worrying about adhering to the principle of making declaration resemble use.


I guess I was only thinking of types, where turbofish comes up. E.g. for declaring generics, like `struct Point::<T>`.


IMO no. I find even :: by itself unpalatable.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: