6 ms·
Reading the comments here it seems like I'm not the only one who thinks some Rust code is pretty syntax-heavy even compared to older systems languages like C an
by alxmdev 7y ago
Reading the comments here it seems like I'm not the only one who thinks some Rust code is pretty syntax-heavy even compared to older systems languages like C and C++.
I wonder if this is in part to further separate application development from system development (slowly paving the way for more verbose but formally verifiable code in core components), and to push more people to write higher level code instead. I can imagine many reasons for why things would be steered this way.
Edit: Bad code example, sorry; thanks for the informative reply! I didn't mean to be unnecessarily negative, just a thought that ran through my head.
- steveklabnik 7y agoI can assure you that Rust's syntax is not designed to further separate application development from system development, if anything, we encourage a way broader audience to learn Rust than just pure systems programmer folks. In general, Rust's syntax is intended to be vaguely similar to C/C++/Java, but with some influence from functional languages where appropriate, and with syntactic forms that work better with type inference. There is very few syntactic forms that are truly novel in Rust (even lifetimes are taken from OCaml's generic syntax, because lifetimes are generics!) That said, fn my_panic(_info: &core::panic::PanicInfo) -> ! { would be something like [[ noreturn ]] void my_panic(&core::panic::PanicInfo _info) { in C++, which is very similar, syntactically speaking. The main differences are: * fn for function declarations * Rust has the return type after parameter list, and adds -> * ! is [[ noreturn ]], less punctuation actually! * no need for the superflous void return type * "name: type" not "type name", which adds a single : I am admittedly very biased, but it seems much more similar than different.
- gpm 7y agoIn addition to this excellent reply, if you were using the type core::panic::PanicInfo commonly (i.e. "twice") you would import PanicInfo at the top of the file use core::panic::PanicInfo and the function would become the much shorter fn my_panic(_info: PanicInfo) -> ! {
- steveklabnik 7y agoYes, and you can do something similar with C++ too; I debated if I should include it or not for this reason. (The semantics are a bit different...) Thanks for bringing it up!
- petschge 7y ago! might be "less" punctuation than [[ noreturn ]] but is a lot harder to google. And why do you need the "->"? That is just more line noise.
- gpm 7y agoBecause `fn foo() u8 {}` doesn't read as nicely as `fn foo() -> u8 {}`? Also because "no return type" is the most common return type, and this way representing "no return type" as omitting the `-> ()` reads nicely: `fn foo() {}`
- lone_haxx0r 7y agoIn my opinion, "u8 foo() {}" looks and reads better than both of those.
- gen220 7y agoI’d agree that it looks better in isolation. I think that the advantage of leading with `fn` arrives when you have paragraphs of functions to scan through. Leading with a consistent word (be it fn, func, or whatever) immediately and disambiguously identifies the line as defining a function (rather than a variable, or whatever), which is a useful landmark to anchor on or pivot from.
- umanwizard 7y agoSo, using grep or a similar tool, how would you find the definition of the function, separately from its uses? In a Rust codebase I could just run `grep -r "fn foo" .` and find the definition immediately. Clearly this doesn’t matter if you’re in an IDE with a working “find definition” feature, but that’s often enough not the case that I find easily greppable definitions to be a gigantic advantage.
- jcelerier 7y agocome on, C++ IDEs had "go to definition" features for literal decades
- klyrs 7y ago> "name: type" not "type name", which adds a single : Sorry for asking a newbie question that's a quick search away, but is there an equivalent to "type name, name, name..."? (I'm biased towards C myself but contemplating a switch...)
- steveklabnik 7y agoThe grammar is let PATTERN: TYPE = Rust’s pattern syntax is richer than just introducing variables. I’m on my phone, so it’s a bit hard to show off all of the things that can be done. In this exact case, though, it usually looks like let (x, y, z) = or with types, let (x, y, z): (TYPE, TYPE, TYPE) =
- klyrs 7y agoYeah, I can live with that.
- somebodynew 7y agoIn C++ unary prefix & is used in an expression to take the address of an object. To declare a parameter of reference type the & would be between the type name and the parameter name (i.e. after PanicInfo/before _info).
- steveklabnik 7y agoGuh, yes, thank you. (It's been a long, long time since I wrote significant amounts of C++.)
- jasonzemos 7y agoWhat I don't understand about all of these languages born out of some inspiration to "do C++ right" which includes the inception of Java, Go, and now this: is the complete disregard for established systems and failure to stand on their shoulders. C++ stood on the shoulders of C and one doesn't need to cite the decades of success as proof; some syntax has proven itself as quite optimal. From what I understand compiler frontends can be augmented to solve all of the problems Rust is trying to solve. Instead Rust is reinventing the entire wheel which is already sharing an axle with Go and Java's entirely reinvented wheels -- not just with syntax, but entire ecosystems from the ground up. I'd like to start seeing a little more reuse of both ideas and effort instead of this present state.
- steveklabnik 7y ago> From what I understand compiler frontends can be augmented to solve all of the problems Rust is trying to solve. This is not correct. If it were this easy, we would have done it!
- jasonzemos 7y agoThen perhaps correct me on what problems Rust is specifically trying to solve? As far as I can tell Rust stands on the shoulders of the LLVM backend- there are existing frontends, like C and C++ but Rust started from scratch. My question is for what purpose? The problems we face today syntactically relate to intuitively expressing global superword-level parallelism to fully leverage AVX-512. No language is currently sufficient in this regard. Was Rust's syntax designed to maximally inform the autovectorizer in the backend to do this? That would be a worthy goal for this kind of investment. Otherwise it's wheel reinvention to me, and I feel Rust is being pushed really, really hard.
- umanwizard 7y agoWriting vectorizable code is certainly important for some use cases, but it’s not relevant for the majority of programming tasks, even in systems/infra programming. Most things outside of numerical work just aren’t bound by the effective width of the core backend. Rust doesn’t have to solve every problem in order to be useful. The major problem it does solve (relative to C++) is explicit compile-time tracking and enforcement of the scope of object validity, preventing (or at least making more unlikely) a class of bugs including use-after-free, uninitialized reads, buffer overflows, dangling pointers, and so on — without requiring a garbage collector. This C++ code, a real mistake I’ve seen in the wild, would be totally impossible to write in Rust without explicitly using the “unsafe” keyword: SomeType* foo() { SomeType x; return &x; } None of this has to do with vectorization, but it’s still important and useful for many tasks. (As an aside: I would be curious to know if there are any languages that make it easier to write auto-vectorizing compilers. Personally I’ve never seen numeric tight loop kernels written without explicit use of architecture-specific intrinsics and/or raw assembly language. But I’ve only worked on that sort of code for at most a few months in my career, so I’d be happy to learn if there’s research in this area.)