|
I believe you'll find the superior title is "I left my compiler in the rain and got Rust". E: But seriously, I've played with it and it's great once you get used to the memory semantics. The community is also surprisingly nice and helpful. I'm not sure how widespread adoption will be, but I hope it becomes a big language. It also isn't afraid to crib all the best features from other languages. Haskell-like type systems, Go's channels, and so on. Linear Zoetrope fucked around with this message at 08:13 on Jan 15, 2015 |
# ¿ Jan 15, 2015 08:00 |
|
|
# ¿ Apr 29, 2024 02:54 |
|
VikingofRock posted:So I'll ask this thread's first stupid question. How does ownership work with arrays, vectors, etc? If I add a Foo to an array or vector, does that array gain ownership over the Foo? Hopefully it's clear what I'm asking here, if not I can try to whip up some code to clarify. Looks like it moves unless you implement copy: http://is.gd/VR7qVk E: Note that it's considered borrowed if you box it too. Linear Zoetrope fucked around with this message at 08:57 on Jan 29, 2015 |
# ¿ Jan 29, 2015 08:52 |
|
Me too. I spent forever yesterday struggling with cryptic lifetime errors until I learned that new methods should return by value and not by pointer. It seems to be a Rust pattern to allow the code requesting the object to dictate its mutability/reference status.
|
# ¿ Jan 29, 2015 09:18 |
|
space kobold posted:Once you get over the initial hurdle of everything bitching at you about lifetimes and learning the ~Rustic~ approach to things, like always returning just a plain bit of value and letting the caller decide if they want to box it (unique pointer to heap allocated memory), stick it on the stack, atomic reference count it, etc, things really start to click and you can appreciate the beauty of what they're trying to do with the language. I have to admit, the thing that confused me about it was largely that once things are immutable they can't really become mutable, and I'm not really clear why it suddenly works when you wrap it in a new function. I have an example to explain my confusion: http://is.gd/l5A2hj I can do code:
code:
However, this gives a compiler error: code:
Linear Zoetrope fucked around with this message at 20:42 on Jan 30, 2015 |
# ¿ Jan 30, 2015 20:38 |
|
Munkeymon posted:Dang, Rust looks way nicer than I remember it looking but From what I've seen, the compiler uses "borrow" properly. All the errors say things like "x has been borrowed by" or "but x was borrowed <here>".
|
# ¿ Jan 30, 2015 22:31 |
|
I tried to make an ECS too. How did you make the list of components? I couldn't figure out how to make a separate list for each component generically.
|
# ¿ Feb 15, 2015 00:10 |
|
Yeah, a macro was my intuition, but I haven't ventured into macro land yet. Looking at yours will probably be educational.
|
# ¿ Feb 15, 2015 00:20 |
|
Y'know, I think the worst thing about Rust is when the borrow checker can't prove something obviously safe is safe. If you have a function like fn get_something(&mut self) -> &mut MyType, and you match on self in the function, you absolutely cannot use any `ref`s on a pattern where you want to return self or Rust will refuse to acknowledge the borrow ends when the match is evaluated and the function returns.
|
# ¿ Feb 27, 2015 09:07 |
|
Here's an example of what I'm talking about. Basically pattern matching on mutable things can be bad: http://is.gd/l61Zav code:
|
# ¿ Feb 27, 2015 22:44 |
|
space kobold posted:The best part about it is that everything in it is more or less feature locked and fairly stable, so every single library in existence isn't going to break every other week so long as they're building against the beta. I did run into a bunch of feature gates I had to switch back to nightly for, though. Some of the stuff in collections is really, really useful. I can live without box syntax, but the collections feature has some really good stuff in it. What's the general stance on using generic parameterization purely for static side effects? That is, parameterizing a function with type T to alter its behavior. I had several algorithms (specifically, a multi-armed bandit solver) and I decided to make a function like: code:
Linear Zoetrope fucked around with this message at 07:55 on May 5, 2015 |
# ¿ May 5, 2015 00:00 |
|
Rust is a language that I think is good, but it's also a language that I think would make a horrible first one, and learning it is much better served by doing than reading. You can make that last point for all languages, but in Rust especially a lot of language quirks like lifetimes and such are really opaque until you wrestle with the compiler and spend a couple hours on Google a few times. It's hard to get a feel for them with a tutorial that simply illustrates correct and incorrect lifetime parameters.
|
# ¿ May 18, 2015 01:47 |
|
Also, I think the more "Rustic" way is to use an enumerated type instead of a faux-null-pointer optioncode:
|
# ¿ Jun 20, 2015 00:08 |
|
Can somebody please help me figure out how to do a tree traversal in a loop rather than recursively? The recursive version is blowing up my stack. The recursive code is essentially: code:
code:
code:
Specifically, it says the problem line is a mutable borrow at the line I call tree.act, which is where it borrows the tree's child out of the node's state->child hash map. Any ideas? I can't do this recursively because unfortunately it overflows the stack due to the depth of the state space. (I'm running monte-carlo tree search on Space Invaders). I can depth limit it, of course, but even if I do that I'll be able to go deeper if I can unroll this.
|
# ¿ Jul 24, 2015 06:59 |
|
It turns out the answer was "use Rc<RefCell<blah>>". That was a fun, if somewhat frustrating, adventure. I eventually went back to the recursive code because it turns out the iterative code had almost no benefit -- the stack overflows at pretty much the same point whether I'm using a homebrewed stack or a recursive one, which I definitely didn't expect!
|
# ¿ Jul 30, 2015 22:30 |
|
Bongo Bill posted:unsafe {} doesn't mean the code within is not safe; rather, it means that the memory safety of the block is promised by the programmer, instead of the compiler. The programmer might be wrong, of course. If you are trying to do something that you know is fine, but the compiler isn't smart enough to prove, that's exactly when you should be using unsafe {}. But it's probably wiser to implement it in such a way that the compiler doesn't need to trust you, wherever possible. Hmm, that's an interesting way to look at it. The language is essentially a constructivist proof in terms of safety, in which parts of the program have two possibilities as far as the compiler is concerned: safe or unproven. When the borrow checker fails something, it's because it can't prove it's safe (rather than proving it unsafe), and the unsafe block tells it that its unprovability is okay. I'd avoided unsafe except for FFI code, but thinking of it that way makes it a bit more palatable to use it when I'm sure something is safe. Though I would imagine that unsafe also prevents it from passing noalias metadata to LLVM in some cases (though the code may still likely be faster than Rc<Refcell<T>>).
|
# ¿ Aug 1, 2015 02:04 |
|
Jo posted:I've been dicking around with Rust 1.0 recently and started fiddling with some Project Euler exercises. One thing that has been biting me is this: at times I'd like to use a variable x as a usize and other times as u64. In this case, I have one function which builds a sieve for the sieve of aristophanes (Vec requiring a usize) and another which does a multiplication into this requiring a u64. Is there an idiomatic way in Rust to use a numeric type, or am I attacking this from entirely the wrong angle? You can do a type conversion with (x as usize), if you're on a 64-bit machine this is probably a no-op at runtime. Though it sounds like your multiplication function should probably be generic over the Mul trait. Unless you're multiplying by a constant. At the moment, unfortunately there's no good way to do generic arithmetic with any constants.
|
# ¿ Oct 10, 2015 01:03 |
|
Just throw type conversions around. IME it's pretty common, at least until associated constants become a thing. That or refactor the prime factor code to take a usize.
|
# ¿ Oct 10, 2015 01:18 |
|
VikingofRock posted:Agreed. It seems like Rust tooling is really taking off, which is very exciting to me. Rust's runtime debugging really needs some work, though. If you have an erroneous `unwrap` you helpfully get the line number of the source code for Option it calls panic! on rather than the actual part of your code. This would be fine if RUST_BACKTRACE wasn't utterly useless on non-Linux systems, on my Windows machine it helpfully prints: code:
Gee, thanks, Rust, I learned so much. It's a good thing 98% of your Rust bugs the compiler catches, and 1.5% are logic errors that result in incorrect computations. Runtime panics happen so rarely this is at least tolerable. I can mostly get around it by always using expect instead of unwrap and making sure each possible panic has a unique error message.
|
# ¿ Jan 7, 2016 00:28 |
|
That's pretty great. The Cavern of COBOL › Rust: error: The Cavern of COBOL does not live long enough
|
# ¿ Jan 15, 2016 05:15 |
|
I'm a bad Rust programmer because once some data structures, especially graphs or trees that require knowing their parents, are involved, I inevitably end up with a couple unsafe blocks. Like, I make 95% of my Rust code safe. I even endeavor to make it effectively impossible to have runtime crashes in FFI wrappers. But a lot of data structures? My feelings end up being, "God drat it, mom! Don't tell me how to live my life! I know what I'm doing!" E: Actually, on a mostly unrelated note, can someone explain Box to me? I mean, I know what it does. It's a lot like a malloc'd pointer in C. I just can never find a place to use it because every time I try it feels like the Box type ends up infecting the return stack of the entire program. Linear Zoetrope fucked around with this message at 00:09 on Feb 20, 2016 |
# ¿ Feb 19, 2016 21:53 |
|
VikingofRock posted:Well if you really want to get fancy, you could do something like what hyper (an http library) does for Responses, and verify this at type level at compile time. Here's an example of what that might look like for this case. Though the immediately obvious problem that jumps out at me with this scheme is it makes loops problematic if you need to assign in those. code:
|
# ¿ Mar 22, 2016 02:21 |
|
Oh yeah, you can do that. But I mentioned loops specifically because for most other constructs you can use a let rebind pattern:code:
I don't know if it's a good pattern, but I use it semi-frequently to create an "x prime" variable where you're deriving a value from some earlier value that's never going to be used again. Linear Zoetrope fucked around with this message at 04:37 on Mar 22, 2016 |
# ¿ Mar 22, 2016 04:33 |
|
I think the Box is getting dropped as soon as svo_create exits, meaning the memory is freed. This is why it's working the first time -- there's really no guarantee how many times it will work, but you're probably getting lucky and then suddenly the memory gets corrupted and everything is terrible. You probably also need to do something like:code:
code:
Linear Zoetrope fucked around with this message at 20:51 on Mar 27, 2016 |
# ¿ Mar 27, 2016 20:42 |
|
Oh yeah, it's definitely the closure, I didn't even notice he was closing over anything, I thought he was using the &Fn as a straight up alias for extern fn.
|
# ¿ Mar 27, 2016 21:00 |
|
VikingofRock posted:In my experience, working with arrays in Rust totally sucks and will likely continue to suck until they add dependent typing (which is planned, but which seems somewhat far-off). For now, I'd just use slices and save yourself the headache. Wait, what? I thought Dependent Typing was a No Go for Rust. I mentioned it a few times in discussions on the issue tracker, and people mentioned they abandoned the idea because it wasn't a "good fit". Which is a shame because I'd really love it. Especially because first-class dependent typing isn't much work away from a full-on theorem prover which means you can prove some pretty strong guarantees for your implementations. (Unless Dependent Typing is a consequence of HKTs? I feel like people wouldn't have vehemently denied plans for dependent types if that were the case though, given that HKTs are very much in the works, though they don't think they can get it done in 2016). Anyway, I have some questions about traits. Or rather, a few trait requirements: 1. Why does Fn require FnMut require FnOnce? Having FnOnce be the base type almost seems backwards to me, especially since this is roughly akin to Take By Immutable Reference -> Take By Mutable Reference -> Take By Move. It feels like taking by reference should be the "least onerous" to implement. But regardless it feels like all these traits should be disjoint, rather than extensions of each other. (Not that you generally implement the Fn traits yourself anyway). 2. Is there any case where you'd have Sync but not Send? It feels like it would have to be a pretty drat wonky scenario, like some of the OS X Cocoa weirdness where certain calls HAVE to be made on the main thread, but sync wouldn't fix that problem. Linear Zoetrope fucked around with this message at 08:40 on Apr 5, 2016 |
# ¿ Apr 5, 2016 08:38 |
|
Arcsech posted:On this note, if anyone has a link to a good explanation of Send & Sync besides the official docs, could you post it? Mutexes are both Send and Sync. If you're doing a fork/join where your data will never go out of scope, you can just create a Mutex and send a reference to each thread. The Arc<Mutex<T>> pattern is so you can send a reference to a bunch of threads, return, and continue doing other stuff in the thread that spawned the other threads.
|
# ¿ Apr 7, 2016 05:12 |
|
It has something to do with your implementation of split_threshold, quads, or the definition of SubImage, because the trivial version works on the Playground:code:
|
# ¿ Apr 7, 2016 23:16 |
|
Here's the problem:code:
code:
code:
I'm probably explaining this very poorly because I don't 100% grasp the intricacies myself. E: You probably want to make this change for the other functions too, but they don't cause this specific function to fail. Linear Zoetrope fucked around with this message at 10:27 on Apr 8, 2016 |
# ¿ Apr 8, 2016 10:23 |
|
gonadic io posted:I own a [T; 8] and would like to access the Ts out of it without copying (this is important). Then I'd like to call a FnOnce(T) -> T on each one and package them back up in an array. I'm very confused by these requirements. Can you elaborate? For small data types, copying a pointer is likely to be no faster (and possibly slower) than copying. For large data types, it will probably have the compiler optimize it to a pointer chase rather than a full copy anyway. Also, is it a different array you're packaging the results in or the same one? Because if it's a different one you at LEAST need to require Clone, otherwise you're just re-implementing Clone with unsafe. Basically, I don't understand why your requirements are what they are, and why you can't use an FnMut. I know there are some issues with being unable to move out of mutable references, so code:
Linear Zoetrope fucked around with this message at 23:48 on Apr 20, 2016 |
# ¿ Apr 20, 2016 23:46 |
|
E: NM
Linear Zoetrope fucked around with this message at 10:38 on Jun 6, 2016 |
# ¿ Jun 6, 2016 10:32 |
|
I mean, there are no guarantees about where memory is freed except that it will always be freed sometime between when it's never referenced again and when it goes out of scope, the compiler is free to optimize around that AFAIK, but it will always be dropped by the time it goes out of scope (except for weird cases involving circular reference counters). I'm not sure what you're really asking about. If you absolutely need to free memory NOW and you can't use scoping to achieve it, that's what drop is for. But yes, you should assume memory is alive until you explicitly call drop or the object goes out of scope. Also, apparently (&str).to_owned() is faster than (&str).to_string() for some reason.
|
# ¿ Jun 8, 2016 00:13 |
|
I don't think this is macro-able, but this is practically the example for compiler plugins in the book (they use Roman Numerals, but it's the same idea of parsing identifiers to make numbers).
|
# ¿ Jul 9, 2016 01:02 |
|
I actually wrote it:code:
XXX = 0b1110_0000 X_ = 0b1000_0000 XXXXXX_X = 0b1111_1101 Right? What I wrote passes all of your test cases, if I got it wrong I at least gave you a point to start from. As a note, if you instead treat everything as starting from the rightmost bytes (that is XXXX is 0000_1111 instead of 1111_0000) you can trivially extend this to an arbitrary usize, but the way you wrote it makes that much harder. Linear Zoetrope fucked around with this message at 01:43 on Jul 9, 2016 |
# ¿ Jul 9, 2016 01:40 |
|
Is the untyped Arena dead? I seem to only be able to get TypedArena on nightly.
|
# ¿ Aug 5, 2016 01:00 |
|
This may be foreign since you're not used to languages with pointer/reference/value distinctions like C++ or Go , but since the function takes a reference to a u32, it can't accept x since it is a u32. You need to give it a reference to a u32. You can do this with the & operator.code:
quote:note: expected type `&mut u32` means. I'm not sure why this was working with a struct, it shouldn't unless the autoreferencing rules on structs are more lenient than I thought (usually auto-(de)referencing only happens in a few places like method calls).
|
# ¿ Aug 22, 2016 02:17 |
|
Asymmetrikon posted:It worked on a struct previously because "a.b" can be implicitly dereferenced to "(*a).b" if need be - this is so operations on references to structs aren't needlessly verbose, since they're very common. Auto-(de)referencing can get really silly if you look at its unsugaring closely, I noted in a Stack Overflow answer recently that if you have the type code:
(It's even worse than this because iter() is actually implemented on the slice intrinsic type and Vec merely implements Deref<Target=[T]>, but it wasn't important to the question) Linear Zoetrope fucked around with this message at 02:49 on Aug 22, 2016 |
# ¿ Aug 22, 2016 02:45 |
|
tinaun posted:https://github.com/rust-lang-nursery/rustup.rs/ will be the offical way to deal with this soon enough, i haven't tried it on windows yet though, but it has support for it. Just installed it, works fine on Windows but if you have MSVC installed you may or may not want to explicitly tell it you want the gnu compiler depending on what libraries you use. It's also better if you generally use cmd/powershell/msys2 instead of just building everything from VS Code or whatever since it's fundamentally a command line application.
|
# ¿ Aug 22, 2016 11:26 |
|
I think Rust's terminal utilities are more targeted for MSYS2 or cmd/Powershell than Cygwin.
|
# ¿ Sep 8, 2016 09:37 |
|
I've been reading that book about Rust and Linked Lists, and they give the following example distinguishingcode:
code:
Is this really true? It doesn't seem like the former should be immune from a null pointer optimization, though it would be more complex to infer.
|
# ¿ Sep 23, 2016 03:06 |
|
|
# ¿ Apr 29, 2024 02:54 |
|
I use the VS Code plugins, which work quite well. The Sublime ones were really buggy when I used them (which wasn't that long ago), they would occasionally save hundreds of temp files in your source directory. There are Eclipse and Visual Studio ones too that support debugger functionality, but I had trouble getting the Eclipse one to work and the Visual Studio one is garbage (doesn't support Cargo, for one).
|
# ¿ Nov 12, 2016 20:47 |