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

Idea: separate types for polar/Cartesian represendations #19

Open
clarfonthey opened this issue Mar 7, 2018 · 5 comments
Open

Idea: separate types for polar/Cartesian represendations #19

clarfonthey opened this issue Mar 7, 2018 · 5 comments

Comments

@clarfonthey
Copy link
Contributor

This might allow users to control which representation is used for the sake of increasing efficiency of calculations.

For example, if a program needs to multiply a large amount of numbers together, they can convert to polar and then back to Cartesian after all of the operations are done.

@shingtaklam1324
Copy link
Contributor

shingtaklam1324 commented Mar 8, 2018

As far as I can tell, there are (at least) two ways that this could be implemented. One is to have separate structs for each type:

pub struct Cartesian<T> {}

impl<T> Cartesian<T> {
    pub fn to_polar(self) -> Polar<T> {}
}

pub struct Polar<T> {}

impl<T> Polar<T> {
    pub fn to_cartesian(self) -> Cartesian<T> {}
}

with methods to convert between them. Another way would be to add a second type to Complex<T>, like so:

use std::marker::PhantomData;

// Representations
type Cartesian;
type Polar;

// R is the marker for represetation
pub struct Complex<T, R> {
    a: T,
    b: T,
    repr: PhantomData<R>
}

impl<T> Complex<T, Cartesian> {
    pub fn to_polar(self) -> Complex<T, Polar> {}
}

impl<T> Complex<T, Polar> {
    pub fn to_cartesian(self) -> Complex<T, Cartesian> {}
}

where a is the real part for cartesian, or the angle for polar, and b is the imaginary part for cartesian, size for polar.

The advantage of the second method would be less code repetition for shared methods, but I'm not sure about the amount of those. The negative would be obviously the more complex code which may bot be as beginner friendly as the current methods.

The advantage of the first method would be that it is clear that these are distinct types, but methods in common must be implemented separately.

Either method would be a breaking change if used as is, but they could both be used behind a wrapper type that is named Complex<T> which has the same methods as the current version.

@cuviper
Copy link
Member

cuviper commented Mar 8, 2018

The branch is currently on 0.2.0-git (pre-release), so breaking changes are possible.

I'm inclined to leave Complex<T> alone, because it aligns with what other languages use, like C's _Complex. In fact, this is why we have a #[repr(C)] on the struct.

We could add Polar<T> while leaving Complex<T> to be Cartesian.

@clarfonthey
Copy link
Contributor Author

I also prefer Complex<T> and Polar<T>; I'll work on this in a bit and see how much of the code I can refactor with it.

@cuviper
Copy link
Member

cuviper commented May 21, 2018

@clarcharr Did you ever experiment with Polar<T>? I'm getting ready to ship 0.2, and one breaking consideration is whether Complex::to_polar and from_polar should use such a new type, or how else that might look. Maybe we'd just add From<Complex<T>> for Polar<T> and vice versa, which we don't need to worry about right now (leaving the current to_polar and from_polar as-is).

@clarfonthey
Copy link
Contributor Author

@cuviper I actually completely forgot, although I have a feeling it would make a lot of computations simpler.

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

No branches or pull requests

3 participants