Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example for simple case of returning Length/Time #33

Open
ndarilek opened this issue Jan 23, 2018 · 3 comments
Open

Example for simple case of returning Length/Time #33

ndarilek opened this issue Jan 23, 2018 · 3 comments

Comments

@ndarilek
Copy link

Apologies if this is documented somewhere and I can't find it. I'm trying to write a distance function that currently returns a distance in meters. I'd like to use this crate to add type safety to this return value, with the eventual goal of representing the distance in feet or other units, or combining it with time units to create speeds/velocities.

Your example shows how to write a speed function. Would you mind demonstrating how one might write a distance function? I.e.:

fn distance(p1: Point, p2: Point) -> f64 {
    // Assume we crunch some numbers and get a distance in meters
    meters
}

I tried making the f64 a Length, but additional type parameters are needed, and if I try braking the build to see what type signature is expected, I get a huge ugly thing that doesn't really give me any clarity. :)

Thanks.

@ndarilek
Copy link
Author

I can't seem to edit the issue title, but to be clear, I don't mean length divided by time, but the case of returning either a Length, Time, or some other typed value that I'm not mathematically combining with another. :) Thanks!

@adeschamps
Copy link
Contributor

I made an attempt at this. I tried enabling impl Trait on nightly so I could return "something that implements Length", but I ran into a bit of trouble. If all you know is that something implements Length, there's not much you can do with it without knowing its concrete type - Length doesn't derive from Add, Mul, Sub, and so on.

Depending on the definition of Point, you could write a distance function using generics that declares all of the trait bounds it needs. It's a bit verbose though. I experimented with something similar a while ago, when I tried implementing a PID controller that was fully generic over its numeric types. The types end up being more complicated than the algebra.

use dimensioned::traits::*;
use std::ops::{Add, Mul, Sub};

struct Point<L>
    x: L,
    y: L,
}

fn distance<L, L2>(p1: &Point<L>, p2: &Point<L>) -> L
where
    L: Sub<Output = L> + Mul<Output = L2> + Copy,
    L2: Add<Output = L2> + Sqrt<Output = L> + Copy,
{
    let dx = p1.x - p2.x;
    let dy = p1.y - p2.y;
    (dx * dx + dy * dy).sqrt()
}

In my own code, I usually just pick a unit system and use its concrete types. So I have a lot of functions that return si::Meter<f64> and so on. If I need values in a different system, conversions are cheap and easy - the concrete types implement Into when appropriate.

@jsbrucker
Copy link

jsbrucker commented Jul 17, 2021

@ndarilek I'm sure you've moved on from this issue at this point but for future users:

Here is a more concrete example* of what I suspect @adeschamps was suggesting at the end of his post above:

extern crate dimensioned as dim;
use dim::si::{Meter, MeterPerSecond, Second};

fn calc_velocity(distance: Meter<i64>, time: Second<i64>) -> MeterPerSecond<i64> {
    distance / time
}

Or if #74 is merged you could use:

extern crate dimensioned as dim;
use dim::si::dimensions::{Length, Time, Velocity};

fn calc_velocity(distance: Length<i64>, time: Time<i64>) -> Velocity<i64> {
    distance / time
}

Now in both cases the uses of i64 could be replaced by just about any concrete type(s) desired, or generics with trait bounds could be leveraged if appropriate.

*I recognize Length divided by Time types weren't actually needed in the OP but it makes for a more interesting example.
Edit: It also appears that basically the same example is already contained in the examples on the readme... I'm not sure how I missed that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants