7 ms·
Bastion of the Turbofish (2020)
- scott_s 6y agoIf 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()
- tooltower 6y agoIt 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?
- kibwen 6y agoAs 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.
- tooltower 6y agoI guess I was only thinking of types, where turbofish comes up. E.g. for declaring generics, like `struct Point::<T>`.
- edflsafoiewq 6y agoIMO no. I find even :: by itself unpalatable.
- baby 6y agoIt’s also never clear where this appears, like a::<b>(c) or a::<b>::c()
- unrealhoang 6y agoin 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.
- kzrdude 6y agoThe 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>
- __henil 6y agoI find specifying type on the left side of assignment operator much easier to interpret. > let x: Vec<u8> = Vec::new();
- adamnemecek 6y agolet x: Vec<u8> = vec![];
- deleted 6y ago[deleted]
- edflsafoiewq 6y agoSpecifically 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"
- scott_s 6y agoYes, and googling around for this rule is what landed me on this epic poem and test.
- ruph123 6y agohttps://turbo.fish/ https://turbo.fish/
- Subsentient 6y agoAm 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.
- scott_s 6y agoIt's a straight-forward rule that (I think) I have mostly internalized. But coming from C++, I was initially mystified.
- vbarrielle 6y agoC++ 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; }
- scott_s 6y agoAnd I have never internalized it! This is me, but for `typename` and `template` in expressions: https://xkcd.com/1168/ https://xkcd.com/1168/
- nzmsv 6y agoI'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#The_typename_disambiguator_for_dependent_names https://en.cppreference.com/w/cpp/language/dependent_name#Th...
- vbarrielle 6y agoYou'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...
- Animats 6y agoThe Rust documentation assumes you know what "snake case" and "camel case" mean. The compiler has opinions about what should be written in each form. Then there's the problem of where to put the lifetime parameters.
- littlestymaar 6y ago> The Rust documentation assumes you know what "snake case" and "camel case" mean. Those are really common terms which have existed long before Rust though. And if you don't know them already, they are easily googleable. The documentation also assumes the reader know what heap and stack are but surprisingly (not) it doesn't bother you. > The compiler has opinions about what should be written in each form. Those are mere lints though. If you don't like compiler's opinion on that subject, you can disable them (with `#[allow(non_camel_case_types)]` for instance, see https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=bc78dce7eead3d94b28ebd0e1bdb7eb0 https://play.rust-lang.org/?version=stable&mode=debug&editio...)) > Then there's the problem of where to put the lifetime parameters. Lifetimes are the one novel concept Rust introduced, then obviously it feels alien at first, because it is. But you end up getting used to it.
- nicoburns 6y ago> The documentation also assumes the reader know what heap and stack are but surprisingly (not) it doesn't bother you. Not sure if it counts as documentation, but the Rust Book actually has a very good explanation of stack and heap. I know because that's how I learnt about these concepts myself.
- wqweto 6y agoIs Rust as first programming language a thing?
- nicoburns 6y agoIt is. There are regularly people new to programming posting questions in r/rust. Although even there most people encourage newbies to consider learning python first. Rust as a first low-level language is very common though. Lots of folks who are interested in getting closer to the metal but are put off by the idiosyncrasies and lack of guard rails of C and C++.
- infogulch 6y agoSo, the rust language developers made some syntax choices in early versions of rust, and when those choices are extended to their natural conclusion the result is that specifying type arguments is a bit more awkward than one might like in some circumstances. This topic is full of nuance, tradeoffs, history, and backwards compatibility; instead of simply lamenting or encouraging endless debate on the choice, the author opted to build a temple around it instead. A piece of art that unapologetically explains the concequence yet still pays homage to the nuance.
- ynik 6y agoExcept that's not where it ends. The Bastion is only a demonstration that it takes a breaking change to get rid of the turbofish. But every new keyword is also a breaking change, and in practice new keywords cause more breakage than the proposed approach for getting rid of the turbofish. Rust editions can easily handle that. Ordering the events on @varkor's attempts to eliminate the turbofish: * RFC 2527 * Bastion of the Turbofish * RFC 2544 If you'd like to know why Rust really still has a turbofish, the huge RFC 2544 thread has the full story: https://github.com/rust-lang/rfcs/pull/2544 https://github.com/rust-lang/rfcs/pull/2544 Important points in that discussion (I'm only linking to the comments summarizing other comments): * Sep 2018: Lang team rejects the change for 2018 edition due to lack of time: https://github.com/rust-lang/rfcs/pull/2544#issuecomment-423338391 https://github.com/rust-lang/rfcs/pull/2544#issuecomment-423... * Jan 2019: Lang team proposes to merge the RFC (accept the change): https://github.com/rust-lang/rfcs/pull/2544#issuecomment-453653184 https://github.com/rust-lang/rfcs/pull/2544#issuecomment-453... * A bunch of people objected, people can't agree on subjective points: https://github.com/rust-lang/rfcs/pull/2544#issuecomment-453769119 https://github.com/rust-lang/rfcs/pull/2544#issuecomment-453... * The discussion got derailed and closed as too heated: https://github.com/rust-lang/rfcs/pull/2544#issuecomment-453796456 https://github.com/rust-lang/rfcs/pull/2544#issuecomment-453... And that's where the project to eliminate the turbofish died. Nobody in the know wants to deal with that much drama, so AFAIK no one has tried again.
- ChrisSD 6y agoHow is a new keyword a *major* breaking change? They can only be introduced at edition boundaries, which means they are opt in. And code can be automatically upgraded to a newer edition by replacing uses of `keyword` with `r#keyword`. New keywords are a relatively minor inconvenience so long as there aren't too many.
- deleted 6y ago[deleted]
- michael_j_ward 6y agoOK. I've been coding in a lot of rust recently, and I can't make heads or tails of why that expression is legal and why the resulting type is (bool, bool). I assume that this is part of the point. Anyone care to spell it out for me?
- michael_j_ward 6y agoAnd here's the answer: https://github.com/rust-lang/rfcs/pull/2527#issuecomment-414635205 https://github.com/rust-lang/rfcs/pull/2527#issuecomment-414... WOW that's certainly a `wat` EDIT: ok - now that I look at it, I understand. My brain was very, very primed to see the <woe, is> as type parameters - and it's late
- cies 6y agoI'm not sure if this is were it came from, but "wat" reminds me of this short funny talk: https://www.destroyallsoftware.com/talks/wat https://www.destroyallsoftware.com/talks/wat Just some context.
- wffurr 6y agohttps://knowyourmeme.com/memes/wat https://knowyourmeme.com/memes/wat
- michael_j_ward 6y agoThat page should have a link to that talk by Gary Bernhardt, because is the reason I reach for the term for "unexpected code behavior." And I'd wager that's true of many in the software community.
- Sharlin 6y agoTo some extent the problem exists in all languages that overload the less than and greater than symbols to also mean angle brackets. C++ infamously has to disambiguate using either the `template` or `typename` keyword in some cases; Rust on the other hand uses the shorter `::` sigil but also more consistently so the programmer doesn’t have to guess or memorize complex rules. Java uses the rather awkward `object.<Type>method()` syntax when you need to explicitly specify a type parameter in a method invocation (which luckily is not very often, and to be fair does mirror the method declaration syntax so there’s that).
- sanxiyn 6y agoIt is indeed unfortunate Rust settled on <> for generics. Looking back, [] is obviously a superior choice. But alas, that train passed.
- qalmakka 6y agoUsing `<` and `>` for generics is not only bad due to their primary meaning as comparison operators, but also due to having to special handle `>>` in the lexer. It took almost 30 years before the C++ standard supported expressions like `std::vector<std::vector<int>>`. For some reason, Bjarne Stroustrup managed to pick the only two character in C that could be merged into a different lexeme.
- chrismorgan 6y agoYet [] still has the same problem while you use [] for indexing: fn a[T](_: T) -> &'static str { "type" } struct b; fn ambiguous() -> &'static str { let a = [|_: b| "expression"]; let b = 0; let c = b; a[b](c) // "type" or "expression"? } So you very probably want to unify indexing and function-calling, which becomes very difficult for Rust because of the whole lvalue/rvalue situation. Because manual implementation of the Fn traits is unstable and no generic implementations exist, I do actually think that this could technically be done (a new edition could go to [] for generics sans turbofish), but it covers a lot of other hazardous ground too (e.g. adding maybe-uninitialised reference types) so that it couldn’t be done for still some years, and I doubt very much that it ever will be (because I doubt many people think it would be worthwhile even if it was free to do, let alone when there’s major implementation cost). I and a few others did try a bit to convince people to shift to square bracket generics in late 2013–mid‐2014, but failed. Certainly the language was in no shape to unify indexing and calling (the best I could come up with was to keep them separate for now, just using the same syntax with the compiler selecting between the mutually-exclusive implementations, with the potential for merging the two in future), so at that time it would probably have retained the turbofish, which didn’t help with convincing people of the superiority of square brackets (no compelling benefit—switching to something unfamiliar, and remember Rust’s weirdness budget was already about expended, without fixing what many felt was the biggest problem with angle brackets).
- chrismorgan 6y ago(2018), not (2020).
- carapace 6y agoI return to my original thesis in re: Rust lang. It's a playground for schmarties. (The fact that it can be used to generate some decent software binaries is a side-effect, used mostly to fool people who might otherwise object to all these schmarties goofing off.)
- carapace 6y agoThe joke didn't land, sorry. Just to elaborate (not troll!) I believe C with tools[1] makes more sense economically than Rust. Rust is popular not because it's groundbreaking but because it's fun. [1] Such as: https://compcert.org/ https://compcert.org/ https://frama-c.com/ https://frama-c.com/ https://www.cprover.org/cbmc/ https://www.cprover.org/cbmc/