Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Jo
Jan 24, 2005

:allears:
Soiled Meat
Speaking of traits, I've defined this type 'Skeleton' which I'm using as the "parent".

code:
trait Skeleton {
	fn load<T : Skeleton>(filename : &String) -> T;
	fn get_all_transform_matrices_at_time(&self, animation_num : u8, frame_time : f32, blend_type : BlendType) -> HashMap<String, Matrix<f32>>;
	fn get_all_transform_matrices(&self, animation_num : u8, frame_num : u8) -> HashMap<String, Matrix<f32>>;
}
code:
111 | 			BVHSkeleton::new()
    | 			^^^^^^^^^^^^^^^^^^ expected type parameter, found struct `bvh::BVHSkeleton`
    |
    = note: expected type `T`
    = note:    found type `bvh::BVHSkeleton`
I'd like to define a 'load' method which takes a filename, since each different skeleton format (BVH, C3D, Blend, etc) will probably have its own skeleton struct.

Problem is the load() method should be returning a physical item, and I think for a trait object to be instanced it needs &self in all the methods. As a workaround, I'll probably get rid of the trait and just have a single skeleton type with a bunch of loaders. Still, it would be nice in future development to know how to do this.

Adbot
ADBOT LOVES YOU

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today

Jo posted:

Speaking of traits, I've defined this type 'Skeleton' which I'm using as the "parent".

I'd like to define a 'load' method which takes a filename, since each different skeleton format (BVH, C3D, Blend, etc) will probably have its own skeleton struct.

Problem is the load() method should be returning a physical item, and I think for a trait object to be instanced it needs &self in all the methods. As a workaround, I'll probably get rid of the trait and just have a single skeleton type with a bunch of loaders. Still, it would be nice in future development to know how to do this.
I think you want
code:
trait Skeleton {
    fn load(filename : &String) -> Self;
    // ...
}
Your original code said that each implementation of Skeleton must define a function which can load a given file as any implementation of Skeleton whatsoever. Type parameters are provided by the caller, remember.

Ralith fucked around with this message at 06:05 on Nov 2, 2016

Jo
Jan 24, 2005

:allears:
Soiled Meat

Ralith posted:

I think you want
code:
trait Skeleton {
    fn load(filename : &String) -> Self;
    // ...
}
Your original code said that each implementation of Skeleton must define a function which can load a given file as any implementation of Skeleton whatsoever. Type parameters are provided by the caller, remember.

Aha! Yes! That seems to have done it! Thanks! :woop:

bobthenameless
Jun 20, 2005

There's also work being done (still pre nightly afaik) on a new feature impl Trait so you can have a function return specifying any type with the trait.

I hadn't heard of it until I read this but it seems cool and good to me :) not really applicable to your problem, but it's in the pipeline.

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today
impl Trait is awesome, yeah, and a must for doing fancy combinator stuff without heap allocation, the possibility of which is one of the things that makes rust really stand out (although a single allocation per Future created across function boundaries isn't a big deal most of the time). The current implementation has some weird type inference limitations compared to Box<Trait>, but hopefully those will be addressed.

Jo
Jan 24, 2005

:allears:
Soiled Meat
impl Trait looks pretty goddamn good. I could have used that a few months back with my compute graph implementation. Would probably have let me split up my node type a lot.

sarehu
Apr 20, 2007

(call/cc call/cc)
Yeah, it would have solved a problem I had before, where something expected a T: FnMut(..), but I had no way to return anything but a Box<FnMut(..)> to pass up to that. (But come to think of it, maybe I could have passed a wrapper of the boxed function?) But now you won't get successively deep wrappers of stuff like that.

bobthenameless
Jun 20, 2005

I haven't played with it yet, but 1.13 for anyone who missed it. the ? operator is pretty slick versus try!s everywhere imo.

i also just like bumping this thread cause rust rules

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today
In the spirit of thread bumps, lately I've been playing with error-chain. It seems like a real improvement over error handling in other languages. I replaced a bunch of "log a descriptive error message, then return an Err" code with "return an error with the descriptive message chained on to it" and my code became significantly more concise, and now I just have a single ten-line block in my main function that pretty-prints a log message for the entire logical chain of failures of anything that makes it that far unhandled, followed by a (runtime-optional) physical stack trace describing where the error came from. The macro for defining all the usual error boilerplate is pretty nice, too.

Malcolm XML
Aug 8, 2009

I always knew it would end like this.
Hell yeah hkt will come so we don't need these ad-hoc monads cluttering up the language

xgalaxy
Jan 27, 2004
i write code
What is everyone using for Rust dev in terms of IDE-like capabilities? I'd like to start looking at Rust more and I develop on both Windows and OSX machines. I see that there are Atom plugins, SublimeText plugins, VS Code plugins, and IntelliJ plugins. Which of these are the most mature and actively developed and supported? Is there any thing I'm missing? I use vim too but primarily on OSX.

Thanks.

Linear Zoetrope
Nov 28, 2011

A hero must cook
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).

Workaday Wizard
Oct 23, 2009

by Pragmatica

xgalaxy posted:

What is everyone using for Rust dev in terms of IDE-like capabilities? I'd like to start looking at Rust more and I develop on both Windows and OSX machines. I see that there are Atom plugins, SublimeText plugins, VS Code plugins, and IntelliJ plugins. Which of these are the most mature and actively developed and supported? Is there any thing I'm missing? I use vim too but primarily on OSX.

Thanks.

The IntelliJ plugin is very good. Also Rust Language Server (https://internals.rust-lang.org/t/introducing-rust-language-server-source-release/4209) is promising.

QuietMisdreavus
May 12, 2013

I'm fine. Nothing to worry about.

xgalaxy posted:

What is everyone using for Rust dev in terms of IDE-like capabilities? I'd like to start looking at Rust more and I develop on both Windows and OSX machines. I see that there are Atom plugins, SublimeText plugins, VS Code plugins, and IntelliJ plugins. Which of these are the most mature and actively developed and supported? Is there any thing I'm missing? I use vim too but primarily on OSX.

Thanks.

From what I've heard, the plugins for VS Code or IntelliJ are probably the best out there in terms of currently-stable IDE-like experiences. The Rust Language Server (linked above) is currently being worked on and from what I can tell it can allow a really nice IDE experience. If you're willing to put your code at the mercy of alpha-level software, it already looks promising.

As far as what to avoid, I've seen multiple people on IRC come in where some Atom plugin messes with their target directory and makes them rebuild all their dependencies all the time. The basic syntax-highlighting one is probably fine, but if you go into the more IDE-like ones you might run into that issue.

(I personally just use vim without even auto-complete and haven't run a debugger over my code so I wouldn't know from personal experience. I'm just relaying what I've heard about on IRC and around the community.)

bobthenameless posted:

I haven't played with it yet, but 1.13 for anyone who missed it. the ? operator is pretty slick versus try!s everywhere imo.

1.13 gave my library a notable compile-time improvement; whatever they're doing with the compiler optimizations is doing something right.

Vanadium
Jan 8, 2005

The ? thing is pretty cool and in general I'm a fan of the explicit Result<> returning, but actually creating a ~good~ error enum or w/e still seems like a lot of pain. Maybe I should just use Strings as errors.

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today

Vanadium posted:

The ? thing is pretty cool and in general I'm a fan of the explicit Result<> returning, but actually creating a ~good~ error enum or w/e still seems like a lot of pain. Maybe I should just use Strings as errors.

Ralith posted:

In the spirit of thread bumps, lately I've been playing with error-chain. It seems like a real improvement over error handling in other languages. I replaced a bunch of "log a descriptive error message, then return an Err" code with "return an error with the descriptive message chained on to it" and my code became significantly more concise, and now I just have a single ten-line block in my main function that pretty-prints a log message for the entire logical chain of failures of anything that makes it that far unhandled, followed by a (runtime-optional) physical stack trace describing where the error came from. The macro for defining all the usual error boilerplate is pretty nice, too.
Still a thing.

Vanadium
Jan 8, 2005

Do you wanna post your code? I mean I've looked at a few of that sorta crate and I still end up getting a bit of a headache each time I think about what type of error I should return and how to structure them.

gonadic io
Feb 16, 2011

>>=
Here's what I use:
code:
macro_rules! get(
	($e:expr) => (match $e { Some(e) => e, None => return None })
);

macro_rules! guard(
	($e:expr) => (if !$e { return None })
);

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today

Vanadium posted:

Do you wanna post your code? I mean I've looked at a few of that sorta crate and I still end up getting a bit of a headache each time I think about what type of error I should return and how to structure them.

Sure. Here's an error module that just wraps multiple other error types:
Rust code:
use std::io;
use capnp;
use config;

error_chain! {
    foreign_links {
        io::Error, Io;
        capnp::Error, Capnp;
        config::Error, Config;
    }
}
Here's one that just has a few regular cases (in fact, this is (the basis of) what config::Error refers to in the above code):
Rust code:
error_chain! {
    errors {
        MissingKey(key: &'static str) {
            description("missing key")
            display("missing key \"{}\"", key)
        }
        MalformedValue(key: &'static str, reason: &'static str) {
            description("malformed value")
            display("malformed value for \"{}\": {}", key, reason)
        }
    }
}
You can use foreign_links and errors at the same time, if you like. There's also various other features but those are the biggies. This produces implementations for the usual traits and various fun methods, per the docs. For something a bit simpler, there's also quick-error, which might be more suited for cases where you specifically want to return a closed set of errors for matching on, rather than just indicate failure in debugging-friendly way.

Ralith fucked around with this message at 19:41 on Nov 13, 2016

Redmark
Dec 11, 2012

This one's for you, Morph.
-Evo 2013
Has anyone tried compiling into Web Assembly from Rust? I tried a Hello World, but the compile time was quite long. I guess there's just too many stages in the pipeline right now?

Also holy poo poo emscripten/LLVM took forever to build. Is that typical for large C++ projects?

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today

Redmark posted:

Also holy poo poo emscripten/LLVM took forever to build. Is that typical for large C++ projects?
Yes, very. Rust's pretty bad about that too, really. Optimizing low-level code is computationally difficult.

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today
The author of error-chain has posted a nice introduction to the newest release which reveals that my use of foreign_links above was somewhat less than idiomatic and makes a better case for why it's worth using beyond saving boilerplate.

DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder

Ralith posted:

The author of error-chain has posted a nice introduction to the newest release which reveals that my use of foreign_links above was somewhat less than idiomatic and makes a better case for why it's worth using beyond saving boilerplate.

Oh wow, this is so cool.

Vanadium
Jan 8, 2005

I love that post, brson owns.

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
Speaking of error-chain, I started using the rust SDL 2 library, which returns some errors as Result<_, String>. What's the most idiomatic way of dealing with those? They work fine by themselves, but I'd like to chain_err them.

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today
You can chain_err any Result type if you have the symbols from a module containing an error_chain! invocation in scope. The method comes from a macro-generated ResultExt trait, and it returns the type of Result defined by that macro. For simple command-line tools, I often just have "error_chain! {}" at the top of the file so I can provide nice detailed information-preserving textual error messages everywhere.

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
It's saying that the Err type of Result needs to implement error::Error, though. I have an error module available, and I can chain_err on other Results as long as their Err implements error::Error. It's just the ones that return Strings instead of real errors that are causing problems.

e: For reference, just in case I'm being real stupid, here's some code that runs into this:

code:
# error.rs

error_chain! {}
code:
# lib.rs

#[macro_use]
extern crate error_chain;
extern crate sdl2;

pub mod errors;

use errors::*;

fn init() -> Result<()> {
    let sdl = sdl2::init().chain_err(|| "Initialization failed.")?;
    Ok(())
}
Where init() returns a Result<Sdl, String>.

Asymmetrikon fucked around with this message at 02:38 on Dec 9, 2016

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today
Ah, right. An easy solution would be to define a struct SDLError(String), impl Error for it, and map_err SDL results into that. Then go smack the SDL crate maintainers for unidiomatic error handling.

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
Mapping errors sounds good, thanks. They not only use Strings for some errors (errors in init() and Sdl::video), they have an error type UpdateTextureError that doesn't implement Error? It's real weird. Probably going to see if they've done something about that and try to patch it otherwise.

DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder

Ralith posted:

You can chain_err any Result type if you have the symbols from a module containing an error_chain! invocation in scope. The method comes from a macro-generated ResultExt trait, and it returns the type of Result defined by that macro. For simple command-line tools, I often just have "error_chain! {}" at the top of the file so I can provide nice detailed information-preserving textual error messages everywhere.

Do you have any good examples of command line tools written in rust?

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today

MALE SHOEGAZE posted:

Do you have any good examples of command line tools written in rust?
The tools I've been writing recently wouldn't make much sense to share, but I hear ripgrep is pretty neat. If you're looking for examples of error-chain use specifically, the best I can do is suggest you page through the reverse dependency list. Maybe Xargo?

DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder

Ralith posted:

The tools I've been writing recently wouldn't make much sense to share, but I hear ripgrep is pretty neat. If you're looking for examples of error-chain use specifically, the best I can do is suggest you page through the reverse dependency list. Maybe Xargo?

Thanks for reminding me of rip grep. I'd been meaning to check out this code review of ripgrep, and it is indeed pretty fantastic for language learners. (Thanks for the other links too, I'll check them out).

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



MALE SHOEGAZE posted:

Thanks for reminding me of rip grep. I'd been meaning to check out this code review of ripgrep, and it is indeed pretty fantastic for language learners. (Thanks for the other links too, I'll check them out).

"stealer" instead of "thief" is a real nails-on-the-chalkboard thing for me. Neat otherwise, though.

DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder
So, I want to parse a protobuf result and then match over the possible return types, but I've got no idea how to to do it.

Protobuf types:

code:
pub fn parse_from_bytes<M: Message + MessageStatic>(bytes: &[u8]) -> ProtobufResult<M>
type ProtobufResult<T> = Result<T, ProtobufError>;
What I'm attempting to do:
code:
mod dispatch {
    use protobufs; // my compiled protobufs
    use protobuf;
    use task;

    pub fn dispatch_msg(m: &[u8]) -> Result<task::Result, &'static str> {
        // match protobuf::parse_from_bytes(m).unwrap() {
        //
        // }
        // Err:
        // match protobuf::parse_from_bytes(m).unwrap() {
        //       ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for `_`
        
	// works
	let pb: protobufs::task::enq = protobuf::parse_from_bytes(m).unwrap();
        println!("{:?}", pb);
        return Ok(task::Result {});
    }
So, basically, I want to parse the protobuf message, and then match over the result, performing a dispatch depending on the type. But I'm clearly going about it the wrong way. Any clues?

I understand that it cant `parse_from_bytes` without a concrete type to return. I think I'm just using the protobuf library wrong but it has very little documentation so I'm just trying to follow the compiler to victory.

DONT THREAD ON ME fucked around with this message at 23:05 on Dec 18, 2016

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today

MALE SHOEGAZE posted:

So, I want to parse a protobuf result and then match over the possible return types, but I've got no idea how to to do it.

Protobuf types:

So, basically, I want to parse the protobuf message, and then match over the result, performing a dispatch depending on the type. But I'm clearly going about it the wrong way. Any clues?

I understand that it cant `parse_from_bytes` without a concrete type to return. I think I'm just using the protobuf library wrong but it has very little documentation so I'm just trying to follow the compiler to victory.

You can explicitly specify type parameters by calling a function with syntax like "parse_from_bytes::<MyMessageType>(m)". You may also get better results from inference once you've actually entered some cases that entail a specific concrete discriminant type.

Alternatively, you could switch to cap'n proto!

I assume you're aware that in real code you shouldn't call unwrap like that, and should instead define an error type which can clearly express/embed the cause of a failure, for example using error-chain.

DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder

Ralith posted:

You can explicitly specify type parameters by calling a function with syntax like "parse_from_bytes::<MyMessageType>(m)". You may also get better results from inference once you've actually entered some cases that entail a specific concrete discriminant type.

Alternatively, you could switch to cap'n proto!

I assume you're aware that in real code you shouldn't call unwrap like that, and should instead define an error type which can clearly express/embed the cause of a failure, for example using error-chain.

boo! I tried that but I was doing parse_from_bytes<MyMessageType>(m). The parse errors probably should have clued me in.

And yeah, I'm still getting used to error handling, but I recognize that by just calling unwrap, I'm failing to handle errors.

gonadic io
Feb 16, 2011

>>=

MALE SHOEGAZE posted:

boo! I tried that but I was doing parse_from_bytes<MyMessageType>(m). The parse errors probably should have clued me in.

And yeah, I'm still getting used to error handling, but I recognize that by just calling unwrap, I'm failing to handle errors.

I'm pretty sure all Rust I've ever written contains ".unwrap() // TODO" and all haskell "fromJust x -- TODO"

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today

MALE SHOEGAZE posted:

boo! I tried that but I was doing parse_from_bytes<MyMessageType>(m). The parse errors probably should have clued me in.

And yeah, I'm still getting used to error handling, but I recognize that by just calling unwrap, I'm failing to handle errors.
The correct ::<>() is called the turbofish and now that you know its name you will never forget it.

gonadic io posted:

I'm pretty sure all Rust I've ever written contains ".unwrap() // TODO" and all haskell "fromJust x -- TODO"
The nice thing about error-chain and the ? operator is that it makes it really easy to implement basic error handling. Just foo.chain_err(|| "foo exploded")? everything and print all the guts of any error in your main function as shown in the quickstart example, and instead of a panic you get a graceful shutdown and a detailed backtrace. Upgrade from strings to matchable enum values as necessary.

Fergus Mac Roich
Nov 5, 2008

Soiled Meat
double edit: Thought I had it figured out. I'm using stable-msvc on windows. What's the recommended setup for debugging? I understand visual debugging is possible with VS2015, but I can't figure out how the setup is supposed to work. I can't get symbols to load for my executable, which I built with cargo run. Do I have an alternative to VS2015?

Tooling has definitely been my major issue working with Rust so far, but my project is still only about ~200 LoC. I haven't had to write specialized data structures or anything.

Fergus Mac Roich fucked around with this message at 10:25 on Jan 1, 2017

Adbot
ADBOT LOVES YOU

DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder
Yeah, refactoring can be super annoying, especially if you're adding or removing a lifetime or something. Fortunately, there's nothing stopping rust from having very powerful tooling, so I think it's just a matter of time.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply