Live data from Hacker News

Patterns for Defensive Programming in Rust

corrode.dev

21–30 of 99 posts

Re: Patterns for Defensive Programming in Rust

#21
post #11

Good article, but one (very minor) nit I have is with the PizzaOrder example. struct PizzaOrder { size: PizzaSize, toppings: Vec , crust_type: CrustType, ordered_at: SystemTime, } The problem they want to address is partial equality when you want to compare orders but ignoring the ordered_at timestamp. To me, the problem is throwing too many unrelated concerns into one struct. Ideally instead of using destructuring t…

You have a good point there, that is better. But it is still, well honestly, wrong. Two orders ordered at different times are just not the same order, and using a typeclass approach to say that they most definitely are is going to bite you in the back seat.

PartialEq and Eq for PizzaDetails is good. If there is a business function that computes whether or not someone orders the same thing, then that should start by projecting the details.

Re: Patterns for Defensive Programming in Rust

#22

Earlier quoted context omitted.

There are. All the big tech companies have them. It’s just difficult to accomplish when you have millions of lines of code.

Is there an industry standard name for these teams that I somehow missed then?

You may wish to search for "readability at Google". Here is one article:

https://www.moderndescartes.com/essays/readability/

(I have not read this article closely, but it is about the right concept, so I provide it as a starting point since "readability" writ large can be an ambiguous term.)

Re: Patterns for Defensive Programming in Rust

#23
Nice article. The problem of multiple booleans is just one instance of a more general problem: when a function takes multiple arguments of the same type (i32, String, etc.). The newtype pattern allows you to create distinct types in such cases and enforce correctness at compile time.

Re: Patterns for Defensive Programming in Rust

#24

Indexing into arrays and vectors is really wise to avoid. The same day Cloudflare had its unwrap fiasco, I found a bug in my code because of a slice that in certain cases went past the end of a vector. Switched it to use iterators and will definitely be more careful with slices and array indexes in the future.

Funny, it's really the same thing, why Rust people say we should abandon C. Meanwhile in C, it is also common to hand out handle instead of indices precisely due to this problem.

Re: Patterns for Defensive Programming in Rust

#25
post #21
post #11

Good article, but one (very minor) nit I have is with the PizzaOrder example. struct PizzaOrder { size: PizzaSize, toppings: Vec , crust_type: CrustType, ordered_at: SystemTime, } The problem they want to address is partial equality when you want to compare orders but ignoring the ordered_at timestamp. To me, the problem is throwing too many unrelated concerns into one struct. Ideally instead of using destructuring t…

You have a good point there, that is better. But it is still, well honestly, wrong. Two orders ordered at different times are just not the same order, and using a typeclass approach to say that they most definitely are is going to bite you in the back seat. PartialEq and Eq for PizzaDetails is good. If there is a business function that computes whether or not someone orders the same thing, then that should start by p…

You can solve this in the general case by implementing the typeclass for the coarser equality relation over an ad-hoc wrapper newtype.

Re: Patterns for Defensive Programming in Rust

#26

Indexing into arrays and vectors is really wise to avoid. The same day Cloudflare had its unwrap fiasco, I found a bug in my code because of a slice that in certain cases went past the end of a vector. Switched it to use iterators and will definitely be more careful with slices and array indexes in the future.

Funny, it's really the same thing, why Rust people say we should abandon C. Meanwhile in C, it is also common to hand out handle instead of indices precisely due to this problem.

It's pretty similar, but writing `for item in container { item.do_it() }` is a lot less error prone than the C equivalent. The ha-ha-but-serious take is that once you get that snippet to compile, there's almost nothing you could ever do to break it without also making the compiler scream at you.

Re: Patterns for Defensive Programming in Rust

#27
post #21
post #11

Good article, but one (very minor) nit I have is with the PizzaOrder example. struct PizzaOrder { size: PizzaSize, toppings: Vec , crust_type: CrustType, ordered_at: SystemTime, } The problem they want to address is partial equality when you want to compare orders but ignoring the ordered_at timestamp. To me, the problem is throwing too many unrelated concerns into one struct. Ideally instead of using destructuring t…

You have a good point there, that is better. But it is still, well honestly, wrong. Two orders ordered at different times are just not the same order, and using a typeclass approach to say that they most definitely are is going to bite you in the back seat. PartialEq and Eq for PizzaDetails is good. If there is a business function that computes whether or not someone orders the same thing, then that should start by p…

I do agree that implementing PartialEq on orders in this way is a bad fit. But it is a synthetic example to make a point, so I tried to keep it in the spirit of the original article (while ironically picking nits in the same vein myself).

Re: Patterns for Defensive Programming in Rust

#28
In Pattern: Defensively Handle Constructors, it recommends using a nested inner module with a private Seal type. But the Seal type is unnecessary. The nested inner module is all you need, a private field `_private: ()` is only settable from within that inner module, so you don't need the extra private type.

Re: Patterns for Defensive Programming in Rust

#29

The tech industry is full of brash but lightly-seasoned people resurrecting discredited ideas for contrarianism cred and making the rest of us put down monsters we thought we'd slain a long time ago. "Defensive programming" has multiple meanings. To the extent it means "avoid using _ as a catch-all pattern so that the compiler nags you if someone adds an enum arm you need to care about", "defensive" programming is go…

For a second I thought you were advocating for something of those, and I had a rant primed up.

Yes. Defensively handle all the failure modes you know how to handle, but nothing else. If you're writing a service daemon and the user passes in a config filename that doesn't exist, crash and say why. Don't try to guess, or offer up a default config, or otherwise try to paper over the idea that the user asked you to do something impossible. Pretty much anything you try other than just crashing is guaranteed to be wrong.

And for the love of Knuth, don't freaking clamp to zero or otherwise convert inputs into semantically different value than specified. (Like, it's fine to load a string representation of a float into an IEEE754 datatype if you're not working with money or other exact values. But don't parse 256 as 255 and call it good enough. It isn't.)

Re: Patterns for Defensive Programming in Rust

#30
post #21
post #11

Good article, but one (very minor) nit I have is with the PizzaOrder example. struct PizzaOrder { size: PizzaSize, toppings: Vec , crust_type: CrustType, ordered_at: SystemTime, } The problem they want to address is partial equality when you want to compare orders but ignoring the ordered_at timestamp. To me, the problem is throwing too many unrelated concerns into one struct. Ideally instead of using destructuring t…

You have a good point there, that is better. But it is still, well honestly, wrong. Two orders ordered at different times are just not the same order, and using a typeclass approach to say that they most definitely are is going to bite you in the back seat. PartialEq and Eq for PizzaDetails is good. If there is a business function that computes whether or not someone orders the same thing, then that should start by p…

Yeah, I immediately twitched when I saw the PartialEq implementation. Somebody is going to write code which finds the "correct" order and ends up allowing someone to order the same pizza but get yours, while you have to wait for it to be made and cooked again.

It's not difficult to write the predicate same_details_as() and then it's obvious to reviewers if that's what we meant and discourages weird ad-hoc code which might stop working when the PizzaDetails is redefined.

Post reply on HN