8 ms·
Seems to rely on at least one known compiler bug (admittedly one open since 2015) https://github.com/rust-lang/rust/issues/25860 https://github.com/rust-lang/ru
by dralley 3y ago
Seems to rely on at least one known compiler bug (admittedly one open since 2015) https://github.com/rust-lang/rust/issues/25860 https://github.com/rust-lang/rust/issues/25860
- dgfitz 3y agoLooking at the syntax in that bug report makes me think I could never learn rust.
- faitswulff 3y agoYou could also think of it as "look at all the weird syntax olympics you need to do in order to trigger a compiler edge case!"
- jrockway 3y agoThe crazier the reproduction, the more interesting the bug. A trivial bug isn't an interesting. A bug where two edge cases interact to do something more than the sum of parts is quite interesting. You learn something about the edge where there's an interaction, and the underlying system as a whole. (Have you ever looked at a fuzzer-generated failing piece of data and not though "oh whoa good point". That's interesting!)
- the_mitsuhiko 3y agoThat is not syntax you would ever see.
- wredue 3y agoI wrote pretty basic rust stuff and had to use lifetime syntax quite a bit. If you are just forcing deep copies all the time, you might not see it often, but if you're just going to deep copy everything always, you’re probably going to be better off with another language to be honest as you’re tossing away much of the benefit of using a language like rust anyway.
- pkolaczk 3y agoI rarely use lifetimes and I don't deeply copy everything. This tool is probably the fastest in its class - does this code look like having a lot of lifetimes, cryptic syntax or deep copying? - https://github.com/pkolaczk/latte/blob/main/src/main.rs https://github.com/pkolaczk/latte/blob/main/src/main.rs - https://github.com/pkolaczk/latte/blob/main/src/exec.rs https://github.com/pkolaczk/latte/blob/main/src/exec.rs There was one fundamental "aha" moment for me when it clicked: move semantics. Once I learned it, suddenly 99% of stuff became simple (including making async quite nice really, contrary to popular HN beliefs).
- wredue 3y agoYou can cherry pick all you want, although I would generally agree that “top level” executables will most likely bump against lifetimes far less frequently than libraries, frameworks, modules etc. I would also generally agree that a single pass through the official book should mostly be enough to be able to read and understand the op.
- pkolaczk 3y agoTherefore I cited the core of the program as well. It also does a bunch of non trivial async processing there. I’ve written at least two other non-toy Rust programs and I haven’t hit “lifetimes everywhere” problem there either. I guess the most lifetime related problems stem from trying to program the Java/Python/JS style in Rust - from overusing references and indirection. If you model your program as a graph of objects referencing each other then I can imagine you have a hard time in Rust.
- datadeft 3y agoI use a lot of deep copy in my every day Rust and the performance is still 10x of my Python that I started to use in 2009.
- mattigames 3y agoThat's like saying you could never learn JS beacuse the following valid JS snippet, when in real life you would never see such thing unless someone its trying to obfuscate the code: [,{a,'z':q|0}[`${a?.x??b}`]]
- deleted 3y ago[deleted]
- riwsky 3y agowat
- FpUser 3y agoThey've just written terse code with lots of single character identifiers. Not the style on would / should use for real life development of readable code.
- secondcoming 3y agoOnce you conquer the headaches and eye-strain, it's not too bad.
- wredue 3y agoOne of my criticisms of Rust is that it’s a very RSI causing language. Very heavy on reaching awkward keys. I mean, a read through the guide makes this very readable, but it doesn’t change that it looks like symbol soup and have lots of awkward repetitive strain to type it out.
- tuetuopay 3y agoThis is one I surprisingly very few complaints about the symbols used. My personal pet peeve are languages that use the walrus operator (:=) for variable assignment/declaration. Those two are on the same side of the keyboard, in the same finger column, so really slow and painful to type. If they were two keys for two different fingers, or better yet, for two different hands, that would be awesome (I have the same issue at work for the warsaw region abbreviated to waw). I write Rust daily and have yet to find such an inconvenience.
- CSSer 3y agoOdd. I'll give you that it's slow to type, but I can't agree that it's painful. Colon is on the home row under my pinky, and equal is next to the delete/backspace key that I hit all day long.
- alpaca128 3y agoDepends on the keyboard layout you're using. Most languages are more convenient on an English layout than certain others because the syntax was most likely designed by someone using a qwerty keyboard. The symbols /[]'\;= are all accessible without modifier key. I have a custom layout on my keyboards which makes each symbol reachable without moving my hands, which made it a lot more pleasant.
- oneshtein 3y ago`&` is a reference. `'a` is a label for a memory area, like goto labels in C but for data. You can read it as (memory) pool A. Roughly, when function entered, memory pool is created, then destroyed at exit. `'static` is special label for static data (embedded constants). `()` is nothing, like void in C. `&()` is an reference to nothing (an address) like `void const *` in C. `&&()` is an reference to reference to nothing, like `void const * const *` in C. `& 'static & 'static ()` is like void `const * const *` to a built-in data in C. `& 'a & 'b ()` tells compiler that second reference is stored in pool 'a, while data is stored in pool 'b. (First reference is in scope of current function.) `_` is a special prefix for variables to instruct compiler to ignore warning about unused variable. Just `_` is a valid variable name too. static UNIT: &'static &'static () = &&(); fn foo<'a, 'b, T>(_: &'a &'b (), v: &'b T) -> &'a T { v } Let's say that `&'a` is from a function `a()`, while `&'b` is from a function `b()`, which called from the function `a()`. The trick here is that we relabel reference from pool `'b`, from an inner function, to pool `'a` from outer function, so when program will exit from function `b()`, compiler will destroy memory pool `'b`, but will keep reference to data inside until end of the function `a()`. This should not be allowed.
- brink 3y agoI think that's the best description of a lifetime I've seen so far.
- dgfitz 3y agoThank you very much for spending time explaining this. It makes more sense with that kind of description. I'm still not sure how long it would take someone like myself to be comfortable and proficient with the syntax. I guess stated another way, I don't generally have issues reading code from a wide swath of languages. If someone plopped me in front of a rust codebase I'd be at the mercy of the manual for quite a long time. Thank you again, sincerely.
- steveklabnik 3y agoRust decided to spend very little budget on syntax. The issue though, is that where it took said syntax from is very wide. & is used for references in a lot of languages. () is a tuple, same syntax as Python 'a isn't even novel: it was taken from OCaml, which uses it for generic types. Lifetimes are generic types in Rust, so even though it's not for an identical thing, it's related enough to be similar. _ to ignore a name for something has a long tradition in programming, sometimes purely as a style thing (like _identifier or __identifier), but sometimes supported by the language. fn name(args) -> {} as function syntax is not SUPER unusual. The overall shape is normal, though the choice between "fn," "fun," "func," or "function" varies between languages. The -> comes from languages like Haskell. <> for generics is hotly debated, but certainly common among a variety of langauges. the "static name: type = value;" (with let instead of static too) syntax is becoming increasingly normalized, thanks to how it plays with type inference, but has a long history before Rust. So this leads to a very interesting thing, where like, it's not so much that Rust's syntax is entirely alien in the context of programming language syntax, but can feel that way unless you've used a lot of things in various places. And that also doesn't necessarily mean that just because it's influenced from many places that this means it is coherent. I think it does pretty good, but also, I'd refine some things if I were making a new language.
- dralley 3y agoYou should treat this the same as you would something like the Obfuscated C competition. Just because it's supposed to compile and run properly doesn't mean it's good code.
- estebank 3y agoYou're right, but in this case it shouldn't compile :)
- GaggiX 3y agoI thought it was just using the totally safe transmute, this one: https://blog.yossarian.net/2021/03/16/totally_safe_transmute-line-by-line https://blog.yossarian.net/2021/03/16/totally_safe_transmute... But I guess there is another trick.
- Georgelemental 3y agoAs noted on that GitHub page, fixing the bug will become possible once rustc adopts a new trait solver: https://blog.rust-lang.org/inside-rust/2023/07/17/trait-system-refactor-initiative.html https://blog.rust-lang.org/inside-rust/2023/07/17/trait-syst...
- Maken 3y agoEverything is always a new solver away.
- TylerE 3y agoa sufficiently advanced new solver. Just like how the lisp guys insisted for decades that a sufficiently advanced compiler would solve all their performance woes. Right up until it became obvious that it couldn't. Feels a bit like early chess engines. They tried to create super sophisticated heuristics to determine move quality, but then one person (or more probably multiple people independently more or less simultaneously) realized it's both easier and better to just do more or less the simplest thing that can possibly work, but do it as much as possible in the allotted time. In other words - don't try to logically decide on the best move with some super advanced set of rules. Just assign a fairly basic and straightforward score based on calculating every reasonble move out 15, 20, 30 moves deep.
- Georgelemental 3y agoIn the case of the trait solver, there is a clear end goal to reach: "the type system should be sound." This is a yes/no question, which you can prove/disprove mathematically. (I suppose chess engines also have an end goal of perfect play, but that is a much harder problem)
- dzaima 3y agoThere's a very simple solver that completes that goal: one that reports that it cannot prove any code as correct. So there must be a secondary goal of "maximize the amount of accepted code", which is a significantly less trivial question.
- nicklecompte 3y agoMy biggest concern with Rust is the sloppiness around the distinction between a "compiler bug" and a "hole in the type system." This is more of a specification bug even though Rust doesn't have a formal specification: the problem is the design of the language itself, not that a Rust programmer wrote the wrong thing in the source code: https://counterexamples.org/nearly-universal.html?highlight=Rust#nearly-universal-quantification https://counterexamples.org/nearly-universal.html?highlight=...
- ggreg84 3y ago> My biggest concern with Rust is the sloppiness around the distinction between a "compiler bug" and a "hole in the type system." That bug is marked as I-unsound, which means that it introduces a hole in the type system. And so are all other similar bugs, i.e., your concern seems to be unfounded, since you can actually click on the I-unsound label, and view all current bugs of this kind (and past closed ones as well!).
- nicklecompte 3y agoPerhaps I should have said "hole in the type theory" to clarify what I meant. To be clear I wasn't trying to imply the rustc maintainers were ignorant of the difference. I meant that Rust programmers seem to treat fundamental design flaws in the language as if they are temporary bugs in the compiler. (e.g. the comment I was responding to) There's a big difference between "this buggy program should not have compiled but somehow rustc missed it" and "this buggy program will compile because the Rust language has a design flaw."
- pcwalton 3y agoBut it's not a fundamental design flaw in the language, nor is it a "hole in the type theory". It's a compiler bug. The compiler isn't checking function contravariance properly. Miri catches the problem, while rustc doesn't.
- nicklecompte 3y ago
- underdeserver 3y agoLooking over the code, it relies entirely on that single bug. On the one hand that's encouraging - you really need to want to trigger it, it doesn't look like a bug that's likely to get accidentally written. Even then, it required a bunch of anti-optimization barriers and stuff to actually be exploitable. On the other hand, one compiler bug and safe, well, isn't I still like Rust.