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

WIP: Automagic number converting #247

Closed
wants to merge 1 commit into from

Conversation

enaut
Copy link
Contributor

@enaut enaut commented Jul 30, 2021

It bothers me a lot that you always have to write t.forward(100.0) instead of t.forward(100).

It turns out to be quite straight forward to make the argument type variable as long as it can be converted to f64 using the From trait.

A sample function would be:

pub type Distance = f64;

fn multiply<T>(x:T) -> Distance where Distance: From<T> {
    let n:Distance = Distance::from(x);
    n*n
}

fn main() {
println!("{:?}", multiply(5));
println!("{:?}", multiply(6.0));
println!("{:?}", multiply(7.3));
println!("{:?}", multiply(244u8));
}

Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=11144955d3f2b0ae26e924612f905dd9

This PR contains a proof of concept implementation for the square example demonstrating different types as argument to forward and right including a custom struct that implements impl From<CustomStruct> for f64.

Would you appreciate that kind of change? Should I convert the whole turtle code base?

@enaut
Copy link
Contributor Author

enaut commented Jul 30, 2021

Oh the auto format changed quite a bit too :( - I'd vote for adopting the default formatting of rust-fmt just for consistencies sake...

@enaut enaut force-pushed the allow-arbitrary-numbers branch from f2e60db to 1bbd751 Compare July 30, 2021 13:38
pub async fn forward(&mut self, distance: Distance) {
pub async fn forward<T>(&mut self, distance: T)
where
f64: From<T>,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also be written as:

Suggested change
f64: From<T>,
Distance: From<T>,

@enaut
Copy link
Contributor Author

enaut commented Jul 30, 2021

Fixed the formatting.

For the generics either T can be used or Angle/Distance both are in this PR

@sunjay
Copy link
Owner

sunjay commented Jul 30, 2021

Hi @enaut, thanks for the suggestion and for taking the time to implement it. Using f64 instead of generics is actually an intentional decision we made when we first created the crate. We're trying to keep the core interface of turtle as simple as possible and avoid generics unless they are absolutely necessary. For example, being able to pass in a color as both a string and a tuple wouldn't be possible without generics, so that's why several color functions take a type that implements Into<Color>.

Writing .0 can be a little bit inconvenient (bothers me too sometimes), but it's something we can live with given that it makes the function signatures easier to explain. This crate is aimed at complete beginners to rust, so sometimes we make trade offs like this.

I've actually filed an issue in the rust repo in the past to make the situation better by at least making sure we have a nice the error message for cases like this. My suggestions to allow 100 to be used as both an integer literal and a floating point literal have not been received well. (People thought I was talking about an implicit conversion but actually I just wanted smarter type inference.) So this is just something we'll have to live with for now.

Appreciate you starting this as a proof of concept so we could discuss it. Unfortunately it's not what we're going for with this crate. Thanks again for taking the time.

@sunjay sunjay closed this Jul 30, 2021
@enaut
Copy link
Contributor Author

enaut commented Jul 31, 2021

That is very unfortunate. I used rust turtle in one course at my school and this proved to be an absolute show stopper (especially for the absolute beginners). - Thus I cannot really use rust turtle in the courses. The students know nothing about float and int and do not understand the error message. It is also not the goal to teach them about the differences as there is only enough time to get a rough idea of programming.

Could this decision be open for discussion again?

@sunjay
Copy link
Owner

sunjay commented Jul 31, 2021

Sorry to hear your students had such a bad experience. If the error messages were confusing we should open up issues on the rust repo and try to get that resolved. I really think this is something that needs to be resolved at the language level (if at all), not in the turtle crate itself. If absolute beginners to programming are learning rust and using this crate, we have far bigger hurdles to teach than explaining that numbers need to end in a decimal point in order to avoid errors.

Integers and floating point numbers are not at all interchangeable in a language like Rust. Even if we allow students to write forward(100) instead of forward(100.0), we'll still need to deal with confusion around rounding when one of them inevitably writes forward(1 / 2) and wonders why the turtle isn't moving. Teaching them to always add .0 isn't convenient, but hopefully it does avoid a lot of confusion at the end of the day to have all numbers be the same type.

Again, I empathize with your students. That's why I filed that issue to improve the error message. I just really don't think this is something to be solved at the level of this crate. Supporting all different numeric types is likely to generate different types of confusion and I don't think avoiding .0 is worth it.

@enaut
Copy link
Contributor Author

enaut commented Aug 1, 2021

Could it be a possibility to add a feature flag? – I agree that in some courses especially at university the difference between number types is essential – however for most turtle applications the difference is nonexistent. Just to stress again: I have said that they have to write .0 on every number. They did, but forgot once. I had that case in every class at least 3 times (with only 10 students). And even when we did more complex things 6 hours into the topic, the students were still hitting that problem.

@enaut
Copy link
Contributor Author

enaut commented Aug 4, 2021

Mhm another option that is independent from turtle-rs would be to create a wrapper crate. Maybe I'll do that.

@sunjay
Copy link
Owner

sunjay commented Aug 4, 2021

Sorry for the late reply. I was going to suggest some kind of wrapper too. If you want to avoid wrapping the whole turtle type and re-producing all the same methods, you could use an extension trait instead:

pub trait TurtleExt {
    fn fwd<T: Into<f64>>(&mut self, distance: T);
    // ...etc...
}

This requires teaching the students to import that trait every time, so you may prefer the wrapper to this, but I thought I'd offer another option just in case.

I'm still pretty firm in my belief that if .0 was causing problems, we should improve the rustc error messages to make them friendlier, not try and solve that in the turtle crate. Creating an implicit conversion with Into<f64> is likely to lead to other problems (e.g. 1 / 10 = 0 because of integer division, 100 + 50.0 doesn't work even though forward(100) and forward(50.0) both do, etc.). I am not convinced that creating that confusion is worth it just to support simpler cases that can be solved by adding .0.

Hope the wrapper you're thinking of using helps your students! Sorry there isn't a great solution to this.

@enaut
Copy link
Contributor Author

enaut commented Aug 4, 2021

Mhm I guess this boils down to personal preference.

I don't mind so much to explain the difference between numbers especially when dividing. I think it totally makes sense that a division does weird things - they know that from earlier school years.

But it does not make sense that the turtle cannot go 100 steps but needs to go 100.0 - It does make perfect sense from a programmers point of view but my students are not programmers and most will never be.
I always try to reduce the amount of concepts they need to learn in a short amount of time.

@enaut
Copy link
Contributor Author

enaut commented Aug 4, 2021

Oh and thanks again for helping me out!

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

Successfully merging this pull request may close these issues.

2 participants