22 ms·
Things Rust shipped without
- 15155 11y agoHow about stdlib-blessed async IO? Or even async/await keywords (simple CPS transformation) a la C#?
- steveklabnik 11y agoWell, it did, but these are things that are good _not_ to have, not things that would be nice to have. If those are things you do want to have, well, we didn't have a design for AIO that we were happy yet, as even the most advanced Rust library, mio, is still a work in progress. https://github.com/rust-lang/rfcs/issues/1081 https://github.com/rust-lang/rfcs/issues/1081 As for async/await, https://github.com/rust-lang/rfcs/issues/388 https://github.com/rust-lang/rfcs/issues/388
- ajkjk 11y agoWhat does "unions that allow access to the wrong field" mean?
- pcwalton 11y agounion foo { int x; float y; }; union foo bad; bad.x = 100; printf("%f\n", bad.y); // undefined behavior (though usually works)
- SomeCallMeTim 11y agoWhich is actually a useful feature in some obscure optimizations, like this fast (approximate) square root: float half_r=r*0.5F; union { float y; int32_t i; }; y=r; i=0x5f375a86-(i>>1); y=y*(1.5F-(half_r*y*y)); return y;
- Scaevolus 11y agoThat hasn't been an optimization for 15 years now. Fast approximate inverse square root is a builtin operation on most FPUs-- on x86, it's RSQRTSS, which tends to be the same cost as a floating point multiply. (for Haswell, it has a 5 cycle latency, and 1 cycle reciprocal throughput)
- SomeCallMeTim 11y agoInteresting, though not useful unless there's a good way to access it from portable C/C++. An __asm__ section or equivalent would work, but would only be useful on a particular CPU -- and different compilers use different syntax for embedding assembly, so that's not ideal either. But where I'd more likely use that optimization at this point is on Arm or ATmega processors. ARM doesn't seem to have an approximate inverse square root, based on a quick check, and ATmega are frequently still stuck with software floating point, so I'd hardly say that the optimization is dead.
- JoshTriplett 11y agoIf you want to reinterpret a float as an integer or vice versa, you can do that easily enough with Rust's unsafe functions: fn approx_invsqrt(r : f32) -> f32 { let y : f32 = unsafe { let i : i32 = std::mem::transmute(r); std::mem::transmute(0x5f375a86 - (i>>1)) }; return y*(1.5-(0.5*r*y*y)); } fn main() { println!("approx_invsqrt(2.0) = {}", approx_invsqrt(2.0)); } Result: approx_invsqrt(2.0) = 0.70693
- kzrdude 11y agoAnd Rust specifies their floats to be IEEE 754, so it always works (endianness may apply though).
- JoshTriplett 11y agoSeems reasonably safe to assume that i32 and f32 have the same endianness.
- kerny 11y agoNo undefined behavior. Perfectly legal since C99 standard.
- _wmd 11y agoCan we please get a quote on this one. If reinterpreting memory via a union is valid in C99, including data vs function pointers, then so would reinterpreting that memory via a cast, which would seem to violate one of the most elementary aspects of the standard (e.g. such a rule would be difficult or impossible to implement on a Harvard architecture machine, which the standard previously made plenty of allowance for)
- pcwalton 11y agoApparently that is correct and I was wrong above (though not in C++) [1]. However, according to the standard, the actual value is unspecified, because float bit representation is undefined. [1]: http://dbp-consulting.com/tutorials/StrictAliasing.html http://dbp-consulting.com/tutorials/StrictAliasing.html
- kzrdude 11y agoPage 83, section §6.5.2.3 of the C11 standard, footnote 95) says > If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type punning’’). This might be a trap representation
- veddan 11y agoGoing through a union is the correct way of viewing one type as another. Casting pointers to accomplish this is undefined behaviour (except for char *) and compilers do TBBA (type-based alias analysis) based on the assumption you don't do it. Famously, the Linux kernel does this a lot and needs to be compiled with -fno-strict-aliasing.
- comex 11y agoThe C standard does not allow casting directly between function pointers and other pointers; they might not even be the same size. Using a union or memcpy will allow you to standards-compatibly reinterpret the bit pattern of a function pointer as a data pointer or vice versa (modulo size differences), but creating the resulting pointer, even without dereferencing it, might cause a crash if the bit pattern is a "trap representation", and in any case dereferencing it isn't guaranteed to do anything useful. ...Not that a portable program has any business trying to read instruction opcodes in the first place.
- Tomte 11y agoIn C you can store a value to a field of a union and then read from a different field. This is usually done to "get the byte representation of a float" or things like that. Except... it's undefined behavior.
- kerny 11y ago> Except... it's undefined behavior. No longer true since C99.
- sinistersnare 11y agoSource please? Or do I need money to get a copy of the standard?
- kzrdude 11y agoGet publicly available draft 1570 of the C11 standard from the committee: http://www.open-std.org/jtc1/sc22/wg14/www/standards.html http://www.open-std.org/jtc1/sc22/wg14/www/standards.html
- tibiapejagala 11y agoLatest standard drafts are usually free for C99 see http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
- rylee 11y agohttps://news.ycombinator.com/item?id=9827417 https://news.ycombinator.com/item?id=9827417
- deleted 11y ago[deleted]
- IvyMike 11y ago> goto (not even as a reserved word) I haven't done this for a while, but once upon a graduate program I wrote a compiler from a made-up-language (MUP) to C. MUP had some strange control structures, and if C did not have "goto", it would have been a lot more difficult to implement those structures. Since then, I have always thought languages should have a "goto" statement that human-written code is not allowed to use. :)
- vezzy-fnord 11y agoAll control flow is ultimately derived from goto (or JMP).
- pcwalton 11y agoIt often simplifies a lot of the compiler implementation if you only have reducible control flow. LLVM is fine with irreducible control flow, because it has to handle C, but rustc uses a CFG for the borrow checker, which is flow-sensitive. You can convert irreducible control flow to reducible control flow, but it can explode the size of the graph in pathological cases. (I don't recall whether the borrow checker actually depends on the control flow being reducible, but some of the possible future improvements we've talked about with "non-lexical lifetimes" definitely do. There are also nasty interactions between RAII and irreducible control flow…)
- gsg 11y agoYeah. Even basic things like building SSA can be done more simply on "structured" CFGs. The benefits are enough that data structure and algorithm designs in the JVM compiler world often take advantage of assuming reducible control flow even though Java bytecode can express irreducible CFGs. Instead, such programs are left to the interpreter.
- cwzwarich 11y agoRust's CFGs are reducible with unbounded treewidth, not structured, because Rust has named exits from loops that nest arbitrarily. Most problems on reducible graphs are not easier than for general graphs, because you can always compute a loop forest (for generalized loops, not natural loops with a single entry point) and just consider a derived acyclic graph.
- andrepd 11y agoWhat about things that Rust shipped without that should have been included?
- luibelgo 11y agoHigher kinded types https://github.com/rust-lang/rfcs/issues/324 https://github.com/rust-lang/rfcs/issues/324
- jpgvm 11y agoThat concerns us less. Rust ships again every 6 weeks.
- moonchrome 11y agoThey do have a constraint of not being able to break backwards compatibility between releases.
- jpgvm 11y agoThis is true. I guess you could say it shipped and is still shipping with many unstable APIs because they so cautious about shipping things they can't take back. I don't see that as a bad thing though, it's not great if you are trying to write Rust programs/libraries -right- now as sometimes you will have to jump through some hoops to only use stable Rust APIs but it will be worth it in the long term.
- Sir_Cmpwn 11y agoIncremental compilation and a non-braindead module system. Breaking changes will be required to fix both, which is why Rust was released too early if you ask me.
- pcwalton 11y agoWhy does incremental compilation require a breaking change? We just sketched a fully compatible design for it last week. I'd also question why the module system is "braindead", of course.
- andresmanz 11y agoI'd like Rust to be shipped without counterintuitive standard library function names and that book with all its style 'recommendations'. And I'd like the Rust compiler to be shipped without that non-snake case warning enabled by default. Language creators won't endear themselves to me by ranting. The problem I have with Rust is _not_ the language itself.
- ericsink 11y agoI like the warnings about style and naming conventions. I kinda wish there were more of them. These warnings can help teams avoid arguments about things that don't really matter very much.
- berkut 11y agoYeah, that's one thing that's really putting me off looking at Rust - the possibility of it enforcing style in the future. Hanging braces style for C/C++ is rarely allowed in the coding standards I've had to use in the past for embedded and real-time stuff in the defence industry, because it can be a source of errors. Aligned opening and closing braces are much more common (in line with ADA's style).
- nrc 11y agoThe compiler will not enforce more style in the future, that will be done by Rustfmt, a separate and optional tool. In fact, it is likely that the compiler lints which enforce style will move out of the compiler and in to Rustfmt at some point in the future.
- Manishearth 11y agoRust doesn't enforce style anywhere. You can turn off all style warnings at once too with `#![allow(bad_style)]` or a command line flag. By default it just warns. That's not enforcing.
- andresmanz 11y agoCome on, even that flag's name is ridiculous. They basically say, for example, that writing camel case, which is the preferred style in most of the projects I've seen, is bad style. Do they like being unnecessarily antipathetic? People think about their personal preferred style for years, and they have very good reasons for choosing them. And in _many_ cases, it's exactly the style that's called bad by Rust's creators. How about making it the opposite, '#![allow(default_style)]'? Or at least '#![allow(non_default_style)]'?
- MrBuddyCasino 11y agoI don't get why those are bad? - random-access strings - auto-increment operators
- steveklabnik 11y agoThe first is bad because of UTF-8, basically. It's unclear what an index should even return: bytes, codepoints, grapheme clusters? Furthermore, because it's a variable-length encoding, it's not O(1) access, which is what [] implies, and since Rust tries to surface the cost of operations, it would be inappropriate for Rust. (Note that Rust _does_ have a ranged syntax here, which returns bytes, and is O(1)) Pre vs post increment just leads to a lot of confusion, and doesn't give you much over `x += 1`, in my opinion. Not sure what Graydon's reasoning is here.
- MrBuddyCasino 11y agoOk, thanks for the details, I suspected as much. My intuition says string indices should be accessible as grapheme clusters (and, additionally, codepoints), bytes are meaningless anyway. Whenever I want to cut and slice a string, I usually want it to be at the boundary of a letter. Yet most languages don't seem to do it this way, strangely enough.
- rspeer 11y agoWell, that's about efficiency. If you want to be able to slice at grapheme boundary n, you have to iterate through the string counting up to n to find out where it is. Might as well just provide an iterator over graphemes in the first place. You can optimize slicing on codepoint boundaries by storing strings internally in a fixed-width representation, like Python does. But now you have to convert encodings all the time just to use UTF-8 for your I/O. And that still only gets you codepoints. It's not a great tradeoff to do it that way. It wastes memory and CPU time, and randomly accessing characters of strings is just not something you actually need to do often enough to optimize for it.
- comex 11y agoJust as additional context, since this seems to come up a lot - that does not mean that UTF-8 is bad. The main alternative is UTF-32, which provides random access to codepoints rather than bytes, but since Unicode graphemes consist of multiple codepoints, UTF-32 is effectively a variable width encoding as well for most purposes, just one that uses much more memory than UTF-8 most of the time and never uses less.
- yurish 11y agoWhat is wrong with UTF-16 support?
- Skalman 11y agoIt's an encoding that isn't good at anything: it's neither ASCII-compatible (like UTF-8), nor fixed-length (like UTF-32), but because most characters require only 2 bytes, developers frequently assume that none require more, leading to bugs when a character eventually is represented by 4 bytes.
- yurish 11y agoI don't know much about Rust and Rust library, so I have a question: what if I what to develop Windows only software in Rust, will I need to convert back and forth between UTF-16 and UTF-8 (or whatever Rust uses in other parts of the library)?
- tatterdemalion 11y agoYes. The Rust std library had to pick a string encoding, and it picked UTF-8 (which is really the best Unicode encoding). The String type is platform neutral and always UTF-8. However, it does provide an OsString type, which on windows is UTF-16. Maybe there is a library - and if not, one could be written - targeting Windows only, and implementing stronger UTF-16 string processing on the OsString type. EDIT: To be clear, Rust's trait system makes this very easy to do. You just define all the methods you want OsString to have in a trait WindowsString, and implement it for OsString, even though OsString is a std library type. One of the great things about Rust is that its trivial to use the std library as shared "pivot" which various third party libraries extend according to your use case.
- Manishearth 11y agoI believe Rust uses WTF-8 as an intermediate format for windowsy things (cheaper), but I'm not sure.
- merlincorey 11y agoHow does one accomplish loop-unrolling as in Duff's Device in rust, if case statements do not fall through?
- steveklabnik 11y agoWell, you generally don't, because Duff's Device isn't generally regarded as a good idea anymore, in my understanding: > It turns out that with branch predictions and the relative speed of CPU > vs. memory changing over the past decade, loop unrolling is pretty much > pointless. http://lkml.iu.edu/hypermail/linux/kernel/0008.2/0171.html http://lkml.iu.edu/hypermail/linux/kernel/0008.2/0171.html
- veddan 11y agoStill, there are cases where fall-through can be useful: int remaining = length % 4; switch (remaining) { case 3: h ^= (data[(length & ~3) + 2] & 0xff) << 16; case 2: h ^= (data[(length & ~3) + 1] & 0xff) << 8; case 1: h ^= (data[length & ~3] & 0xff); h *= m; }
- steveklabnik 11y agohttps://github.com/pythonesque/fallthrough https://github.com/pythonesque/fallthrough can emulate the fallthrough style if you really, really want to have it. It seems like it hasn't been updated in a while, though.
- deleted 11y ago[deleted]
- Jweb_Guru 11y agoIn the post-1.0 world, a repository not having been updated for a few months doesn't automatically mean it no longer works :P
- 11y ago
- saboot 11y agoRust also shipped without reflection, which was available in the beginning. I was a bit disappointed as it was something I would have made use of for serialization.
- FrozenCow 11y agoWouldn't it be better to create serialization functionality at compile-time? In the Java space some libraries are moving to compile-time code generation instead of relying on reflection. It is a huge win, since a lot more can be checked beforehand. Dagger 2 is a good example how it can be beneficial. It provides dependency injection at compile-time, which will in turn check whether all dependencies are satisfied. I haven't seen this being done at compile-time before, but it is definitely a step up from reflection-based DI. I'm not sure whether macros of Rust can provide such functionality, but the developers seem conservative when it comes to adding functionality. That seems like a good thing.
- saboot 11y agoI was referencing at compile time, yes. How does Dagger generate the code? Does it run an executable first? Yes, in C++ there is a similar library called ROOT which generates c++ files called "dictionaries" storing class information by running an executable over the files. I don't see (or understand) the downsides in providing the functionality for performing those steps at compile time though. The developers of ROOT are currently pushing for it to be included in C++17 (or beyond).
- mercurial 11y agoSometime I wish no runtime reflection was available to the programmer at runtime in Java, this would prevent people from being tempted to use brittle runtime magic. Of course, you would need a solid macro system instead. And thanks for the pointer to dagger, this looks like an interesting alternative.
- wyager 11y agoHow do you imagine that reflection would be useful for serialization in Rust?
- kazinator 11y agoI used Common Lisp's goto (tagbody with go) to implement portable tail recursion: a "tlet" construct that looks like the "labels" syntax for defining a local function, but is just a stackless goto thunk with parameters. http://www.kylheku.com/cgit/lisp-snippets/tree/tail-recursion.lisp http://www.kylheku.com/cgit/lisp-snippets/tree/tail-recursio... This also provides some facilities for doing cross-module tail recursion among top-level functions. Here, continuation to the next function is provided by wrapping the function call in a closure, performing a non-local exit which abandons stack frames up to a dispatch loop, which then invokes the closure.
- alfiedotwtf 11y agoPerfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. -- Antoine de Saint Exupéry
- sklogic 11y agoLack of `goto` is a huge disadvantage for a language with macros. Pity they did not want to provide something like `unsafe` keyword which would enable all the dirty, dangerous, high-performance stuff.
- titanomachy 11y agoRust has an `unsafe` keyword, but goto isn't one of the things it enables.
- frivoal 11y agoOne of the things Servo (the web browser engine written in Rust) has not decided to write from scratch is a (high performance) js engine. If they did, they might have more feedback on this kind of things.
- shawn-butler 11y agoI would add Ropes: https://github.com/rust-lang/rfcs/issues/653 https://github.com/rust-lang/rfcs/issues/653 Given the frequency of manipulating large bodies of text in contemporary programming I do not agree it is best left to a library implementation. Without ropes as core std average rust developers will do what they did in java, c++, objC and simply use and abuse std::strings in all cases including those where it will perform poorly. https://en.wikipedia.org/wiki/Rope_(data_structure) https://en.wikipedia.org/wiki/Rope_(data_structure) [pdf] http://www.cs.rit.edu/usr/local/pub/jeh/courses/QUARTERS/FP/Labs/CedarRope/rope-paper.pdf http://www.cs.rit.edu/usr/local/pub/jeh/courses/QUARTERS/FP/...
- ewillbefull 11y agoI think some progress will be seen in libraries first, namely things like tendril. https://github.com/servo/tendril https://github.com/servo/tendril
- jlarocco 11y agoI'm sorry, but I have a hard time being impressed by any of those. They're all just fixing things that were busted in C. I mean good for Rust, but C is a pretty low bar. Does any language created in the last 20 years make those same mistakes?
- geofft 11y agoRust is the first language that fixes all of these things, can be used as a replacement for all of C's use cases (including ABI-stable libraries, kernels, etc.), and has a sufficient community / mindshare that you can expect libraries to exist in the language for functionality that you generally expect to find in libraries. Maybe we should be embarrassed as an industry that it took us 20 years to get there, yes.
- beeforpork 11y agoIf Rust misses 'goto', it is not suitable for translating SSA into it, which most compilers natually produce (also for LLVM, obviously). I.e., it is not suitable for being used in a compiler backend. Here, it can never fully replace C. 'goto' should not be daemonized, we know better today.
- eddyb 11y agoI don't follow, why would SSA need to be translated into an input language? LLVM used to have a C backend, yes, but that hasn't been maintained for a while now.
- sklogic 11y ago> I don't follow, why would SSA need to be translated into an input language? Rust is a meta-language with very powerful macros in it. What is a macro? Macro, essentially, is a compiler. You can have some petty macros implementing tiny syntax sugar on top of your language, that's totally fine, but that's not their purpose. The real metaprogramming kicks in when you implement very high-level eDSLs on top of your macros. And for this sort of things, having a proper compilation pipeline is a must. Many eDSLs may end up being represented as an SSA. E.g., I'm doing this with a Packrat eDSL - it pays to represent its intermediate language as an SSA for doing some high level optimisations before spitting out the host language code.
- DannyBee 11y ago" Next time you're in a conversation about language design and someone sighs, shakes their head and tells you that sad legacy design choices are just the burden of the past and we're helpless to avoid repeating them, try to remember that this is not so." I think rust is neat, but this is somewhat arrogant. Rust is amazingly young. 10-20 years from now, when rust hopefully has bajillions of users, if this is still true, then you can say it. I mean, do you really believe that Rust won't have things that turn out to be warts from 1.0 it can't remove 10-20 years from now?
- justthistime_ 11y agoExactly. It's not like we don't know plenty of mistakes yet, which will bite them a few years down the road.
- andresmanz 11y agoOn the whole, it's that arrogance that keeps me away from Rust - for now.
- hyperpape 11y agoI think you're misreading this. I read it as saying that these things are sad design choices in many similar languages, but that Rust has avoided them. Nothing follows about them not having included other sad design choices that they're unaware of. The point is that you can at least try to avoid the things you view as sad design choices--you're not necessarily stuck with them.
- Jweb_Guru 11y agoI know that Rust has warts. That doesn't mean it has to have the same warts.