#Would like some advice on what a function's return type should be

15 messages · Page 1 of 1 (latest)

unique maple
#

Hi! I'm making a 2D tilemap struct (for games that use tilemaps) that will hold tile data - and I'm currently trying to make functions that will allow you to get the tile data.

However, I'm stuck on what type to return. As it stands, some errors can happen while attempting to get the tile data:

  1. The tile position that the user specifies is not within the bounds of the tilemap
  2. The tile index (calculated from a TilePosition struct which holds two numbers) would overflow a usize.

Because of these two issues, I'm stuck on what the return type of such get_tile functions should be:

  1. A Result<&Option<T>, SomeErr> (where SomeErr describes the above errors)
  2. A Option<&Option<T>> (The outside option is None if one of the above error occurs, and Some(_) otherwise).

(The inner Option<T> is because of how the tiles are stored - in a Vec<Option<T>> - and because a tile not existing is not an error. Additionally, I plan to include impls of the Index and IndexMut traits, that will panic upon an error.)

Primarily, I'm not sure whether to consider the tile index calculation (something that's more internal than anything) an error that should be returned. Could anyone provide any advice here?

#

Would like some advice on what a function's return type should be

keen basalt
#
  1. id return a Result if there are multiple ways a function can fail, Option if theres only one
  2. &Option<T> is an uncommon type to return and use, Option<&T> is more useful
  3. personally id return either a Result<&T, Error> or Option<&T> instead of those two
unique maple
#
  1. It sounds like I'd want to use Result then?
  2. I use &Option<T> because get_tile_mut() returns a reference to the tile's slot - a &mut Option<T> - which means you could use get_tile_mut() and then simply mutate the results, and your changes would show up on the tilemap immediately.
  3. If I return a Result<&T, SomeErr>, that would imply that a tile not existing is an error - even though it's not. Meanwhile, if I use Option<&T>, that would run counter to what I put above in #2.
shut elbow
# unique maple 1. It sounds like I'd want to use Result then? 2. I use `&Option<T>` because `ge...

"Reference-to-Option" and "Optional-reference"* are both ways to represent "a reference to a value that may or may not be there" in Rust. So which one should you use in your APIs? Hear me spoil my answer within the first 10 seconds, and then stick around to get real nerdy about a topic you may have never spent 15+ minutes thinking about before. ...

▶ Play video
unique maple
#

Hmm. I'm actually starting to wonder if an overflowing tile index is even a concern. When creating the TileMap, you specify a MapSize (a struct with two usizes), and that gets converted into a tile capacity - specifically a single usize.

For TilePosition to be a valid position, it would have to be within the bounds of the map in both directions. And because I check if it's within those bounds before converting it, and by this point we know we have a valid MapSize, TilePosition couldn't possibly convert to an overflowing index without also being outside the bounds of the map.

#

Thus, my "is this position outside the map bounds" check already technically covers the overflowing index bit.

#

@shut elbow Still, that begs the question of how I would differentiate between an erroneous input value (a position outside the map bounds) and a tile that was simply never set. How would I do that?

shut elbow
#

and a I would use a Result<&mut Option<T>, OutOfBounds> probably

unique maple
#

I see. Thank you.

unique maple
#

@shut elbow As an aside, I'm considering reworking the TileMap struct to simply use a Vec<T> instead of Vec<Option<T>> - so that people can decide to use TileMap<Option<T>> if they want the possibility of it being None.

#

However, I've got to do some mental processing about the effects of such a change, before I do that rework

shut elbow
unique maple