0

I'm working on a library which will provide a trait for axis-aligned bounding boxes (AABB) operations. The trait is declared like this:

trait Aabb {
    type Precision : Zero + One + Num + PartialOrd + Copy;
    // [...]
}

I don't care which precision the user chooses, as long as these constraints are respected (though I don't really expect integer types to be chosen).

I'm having trouble using literals. Some operations require constant values, as an example:

let extension = 0.1;
aabb.extend(extension);

This doesn't work because Aabb::extend expects Aabb::Precision and not a float. My solution was something like this:

let mut ten = Aabb::Precision::zero();
for _ in 0..10 {
    ten = ten + Aabb::Precision::one();
}

aabb_extension = Aabb::Precision::one() / ten;

This works, but I need to resort to this every time I need a specific number and it is getting cumbersome. Is this really the only way?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Luke B.
  • 1,258
  • 1
  • 17
  • 28

2 Answers2

1

In this case, I would recommend that you create your own trait and provide default implementations of the methods.

For example, I would naively imagine:

trait ApproximateValue: Zero + One {
    fn approximate(val: f64) -> ApproximateValue {
        // some algorithm to create "val" from Zero and One
    }
}

then, your Precision associated type will have a bound of ApproximateValue and you will just call Precision::approximate(0.1).

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • I can't compile that, it says `missing associated type 'Output' value` in the return of `approximate`, changing it to `ApproximateValue>`simply pushes the error forward. – Luke B. Aug 18 '16 at 21:02
  • @LukeB.: In the code I proposed there is no `Output` and `ApproximateValue` has no associated type... so I would need to see your code to understand what's going on (you can use the Rust playpen for example, or a gist). – Matthieu M. Aug 18 '16 at 22:15
  • I just copied and pasted your code (and added an `unimplemented!()` call). I tried just pasting your code in the playground but can't compile it there either, though the error is different `the trait 'ApproximateValue' cannot be made into an object` – Luke B. Aug 18 '16 at 22:24
1

I need to resort to this every time I need a specific number and it is getting cumbersome. Is this really the only way?

Basically, yes. Unless you can answer the question of "how do you support converting a literal 0 to MyCustomTypeThatImplementsTheTrait".

You can't have it both ways — you can't ask for something to be generic and then use concrete literals.

You can have different workarounds. Providing base values like "zero" and "one", or having a "convert a specific type to yourself" method, for example.

You could also re-evaluate what you are attempting to do; perhaps you are thinking at too low a level. Indeed, what does it mean to "extend by 0.1" a type that represents points as floating point values between 0 and 1?

Maybe it would be better to have an expand_by_percentage method instead, or something else that makes sense in the domain.


See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • I extend by an arbitrary value because the algorithm requires AABBs with a minimum size, `0.1` is only bad if you are using something like `0.0001` to represent a meter. But then, you will run in a lot more issues than just an unoptimized tree. Anyway, thanks for you answer, I'll stick to manually building the values. – Luke B. Aug 19 '16 at 03:00
  • @LukeB. If you are allowing a generic type to be passed, then you can't make a blanket declaration about how the type implements the trait or what types of values will be well optimized by the type. – Shepmaster Aug 19 '16 at 03:02
  • Can you give me an example of something that could go wrong? If you dont implement the trait correctly it is not going to work, but I cant really defend my code against that can I? – Luke B. Aug 19 '16 at 16:26
  • Unless you mean someone using something like i32 instead of f32? If so you are probably right, I haven't tested my code using integers yet so I don't know how it is going to react – Luke B. Aug 19 '16 at 16:52