Developing guidelines for prototyping with Rust

Hello, folks! I'm trying to put together a list of shortcuts and other tricks, in order to discover and document a subset of Rust that is more suitable for rapidly prototyping ideas. I'll explain:

Rust's focus on correctness and memory layout has a number of laudable benefits, for example: "If it compiles, it (generally) works!" It also forces its users to consider things that they might not, otherwise, and the quality and design of the code becomes all the better for it.

However, these same qualities make Rust less pleasant for sketching out and exploring an idea when compared to a language like Ruby, where one can extremely rapidly get something quick and ugly working, and then refactor to a better design, once the problem is better understood.

So, in practice, I find myself prototyping ideas for Rust programs in Ruby or Node.js if the idea involves async stuff, and then once I discover what I'm actually building, and am happy with the overall design, I port the prototype to Rust.

This works well enough, but it'd be great if I could just do the whole thing in Rust! With that in mind, I'm trying to compile a list of ideas to make Rust a bit easier to hack around with when correctness and performance are explicit non-goals. This is what I have so far, and it ain't much! Help?

  1. Problem: The borrow checker is really getting in my way! Solution: If the data is mutable, just Arc it. If its immutable, .clone() it. Play zero-copy golf later!
  2. Problem: The compiler is complaining about size not being known at compile-item. Solution: Box it! Fuck it, Box everything! Throw it all on the heap!
  3. Problem: The compiler is asking me to explicitly consider every possible-but-unlikely failure state. Solution: .unwrap() all the things! Happy path is good enough for now!

What else could we add to this list?

In conclusion, I'd like to prototype in a deliberate flavor of Rust that is amenable to rapid development and experimentation, and then refactor to "good" Rust, later. What might this flavor look like?

3 Likes

Ah yes. Many times over recent years I have explored an idea in Javascript and node.js. When it's massaged into a working state that looks reasonable it's time to reimplement in C++.

In the old days we used to plan ahead and exchange ideas using pseudo code, often written by hand on paper. With JS, Python and the like we have pseudo code that runs!

Like you I started to speculate how one would do this kind of quick hackery in C++.

It occurred to me that what it requires is a class hierarchy that represents all the types of JS and allows all the operations between them that JS does. Producing all the same wonky results that JS can!

But then there are complications with async and or threads to think about...

2 Likes

My favorite is the unimplemented!() macro for paths that are required to be implemented but that you're not ready to think about yet :slight_smile:

9 Likes

Writing the happy path for a match then put a catch all in and see what happens.

match whatever {
    Happy(foo) => {...},
    bar @ _ => println!("{}", bar),
}
3 Likes

I'd say not unwrap, but expect (with different error messages) - because unhappy path could almost always trigger, and you don't want to guess which one is now.

4 Likes

The idea here seems to boil down to the possibility of using Rust in a similar casual and speedy fashion to the way one hacks on an idea in Javascript, Python etc. With none of that annoying type checking and lengthy build times.

So how about using a dynamically typed scripting language implemented in Rust? To that end there is Dyon http://www.piston.rs/dyon-tutorial/introduction.html

Now Dyon aims to have a fast hack/run dev cycle but it maintains the mutability and aliasing checks of Rust. That might seem to go against the grain of the idea here, but it means you are not going to be creating scripts that implement a lot of mutation and aliasing that does not move to a Rust implementation easily.

I have no idea if Dyon fits the bill of the OP here, having not tried it yet, but it looks interesting and is being maintained so I thought I'd throw the idea into the ring.

1 Like

but then you have to think about actual error messages ! line numbers ftw :grinning:

for me, type checking is on the side of things that help me prototype better, instead of getting in the way, as it prevents the dumbest kinds of mistakes like wrong argument order (with notable exceptions such as having to cast between integer types :yawning_face: )

1 Like

Yeah, can be.

When I said "annoying type checking" I was really thinking of all that syntactic and semantic baggage you have to deal with when riffing on code in a language like C, C++, Rust, etc. With something like JS you just blurt it out.

It's the reason we had pseudo code back in the day. You could scribble down the idea without actually having to write a ton of assembler and get it to run properly.