6 ms·
Their initial explanation is bounds checking specifically. While most abstractions are zero-cost, bounds checking isn't. I do wish there were a way to track ex
by Zarel 7y ago
Their initial explanation is bounds checking specifically. While most abstractions are zero-cost, bounds checking isn't.
I do wish there were a way to track expectations about integer ranges in a type system, but there currently aren't.
- wbl 7y agoMight I intrest you in dependent types? Sadly we don't even have a self hosted compiler yet.
- Zarel 7y agoI really like dependent types as a concept! But they're not really in any mainstream languages, so I haven't had much opportunity to play around with them. :(
- steveklabnik 7y agoBounds checking is a “zero cost abstraction” in the sense that it is both “pay for what you use” and “you couldn’t implement it yourself any better.” That said, the implemention is not as fast as it theoretically can be, because the compiler isn’t always removing bounds checks that are provably true. When const generic lands, you will be able to make those assertions! A basic implementation is in nightly.
- jnordwick 7y agohow do you not use bounds checking? (unsafe like get_unchecked doesn't count because then you can say that about almost every rust feature).
- deleted 7y ago[deleted]
- steveklabnik 7y agoYou're mis-understanding what "you don't pay for what you don't use" means. It means that a program that does not contain [] in it does not include code for []. There's no "mandatory runtime" code for []. It doesn't mean you can use [] in some special way and somehow get less code. And even if we were talking about your understanding, I don't see why get_unchecked would be disqualified. unsafe is a part of the language for a reason.
- jnordwick 7y agoI know, the meaning of "zero cost abstraction" is really "zero cost to not use the abstraction." But that's like saying if you don't use rust you don't pay for it. Just because there is the unsafe escape hatch in the language, you don't get to label the language as zero cost abstraction. Because practically speaking there is a lot more runtime cost to rust than people will tell you. Many langauges (almost anything without a runtime) meet that definition of zero cost abstraction then.
- jzoch 7y agoWhat languages dont have a runtime? Even C has one (albeit a very small one). Nobody labels Rust the language as a zero cost abstraction (thatd be silly - there is a cost to learning it!). Rather, they try to provide zero cost abstractions. A great example is that there are no green threads in rust because they consciously removed them as they penalized rust performance regardless of whether said people used green threads or not.
- lilyball 7y agoYou still seem to be missing the point. If you use a Rust construct that does bounds-checked accesses, you're explicitly using bounds checks. You're not paying for anything beyond the bounds checks that you're using. If you use a Rust construct that elides the bounds checks (e.g. get_unchecked), there are no bounds checks, and you don't pay any cost for the fact that Rust supports a bounds-checked subscript operator. If you want to compare Rust's subscript operator, do so with an explicitly bounds-checked version of the C code. That's the appropriate comparison for "zero-cost abstraction". Because the whole point of "abstraction" is it's not a change to the observed runtime behavior, it's just a language abstraction.
- dbaupp 7y agoThis is taking zero-cost abstraction to the extreme, and I think waters down the concept to the point that it almost isn't useful. One can argue that any feature is a zero-cost abstraction for the exact set of trade-offs it has (in the limit: "you couldn't implement a feature that executes this exact sequence of instructions 'mov ...' any better if you did it by hand"). I think focusing on a hypothetical perfect coder is more useful, someone who never fails an assertion or bounds check. This person does not need any safety/convenience features (unlike us real humans), but they can still use some such features without a penalty. Bounds checks are not one of them. (But... At least they don't have much of a pervasive/whole program cost.)
- imtringued 7y agoBounds checking is not an abstraction. Therefore you are the one who is twisting the word "zero-cost abstraction" to cover things it doesn't cover.
- haberman 7y agoGC isn't an abstraction either. By that argument, you could claim that you have zero-cost abstractions even if you have stop-the-world GC.
- iopq 7y agoIt does abstract over memory management quite a bit taking out the implementation details. What is an abstraction?
- dbaupp 7y agoHm, I'm not sure I understand. I don't think I was the one to call bounds checking an abstraction in this thread.
- steveklabnik 7y agoMaybe! I think that the concept is a bit more focused than most people think it is. I can appreciate this perspective though. It's a fuzzy concept, so there's decent room to poke and prod around the edges :)
- michael_j_ward 7y agoWhat exactly does "you couldn't implement it yourself any better" mean if the current implementation isn't as fast as it could be? Or are you saying that the current implementation fails to live up to the "zero cost abstraction" goal?
- steveklabnik 7y agoThe implementation of bounds checking couldn't be written any better: https://doc.rust-lang.org/1.37.0/src/core/slice/mod.rs.html#2643-2689 https://doc.rust-lang.org/1.37.0/src/core/slice/mod.rs.html#... #[inline] fn get(self, slice: &[T]) -> Option<&T> { if self < slice.len() { unsafe { Some(self.get_unchecked(slice)) } } else { None } } This is exactly how you'd write the feature, by hand, if you were implementing the language. That the optimizer could, but does not, do as much optimization as it theoretically can, means that it has more work to do. But that's different than the feature being written in a sub-optimal way.
- michael_j_ward 7y agoI don't know if you edited your comment, or if it was just my pre-coffee reading comprehension missed the part "because the compiler isn’t always removing bounds checks that are provably true." I understand now, gracias.
- steveklabnik 7y agoI don't think I did, but I am very empathetic to pre-coffee reading comprehension woes :) Glad we got it sorted.
- rkagerer 7y agoThis got me wondering why we don't include dedicated hardware for bounds checking in CPU architectures. Intel made an attempt with MPX but from a brief glance on Wikipedia it looks like a fail (slower than pure software approaches like AddressSanitizer, among other issues).
- imtringued 7y agoProbably because it doesn't matter. The only important thing is to make sure that the hardware doesn't mis-predict the bounds check.
- fluffything 7y agoFWIW it isn't hard to write safe Rust code that elides bound checks, but one needs to write proper code. If one pin points a performance issue due to bound checks, it is also always trivial to disable them in a safe way by writing proper `unsafe` code when it makes a difference.
- bjourne 7y agoThere are! It is done in compiled Lisp and Scheme runtimes such as SBCL to remove provably redundant bounds checking. For example, in (when (< x 4) (when (>= 0 x) (...))) SBCL will infer that if x is an integer, it must have one of the values 0, 1, 2 or 3. The knowledge is useful because if x is used as the index of an array containing 3 or more items the bounds checking can be elided.
- tom_mellior 7y agoCompilers do that, yes. But I think the grandparent wanted to express this at the source level, as an annotation to a type.