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

Are stub lib.rs files a good idea? #200

Closed
IanWhitney opened this issue Sep 11, 2016 · 10 comments
Closed

Are stub lib.rs files a good idea? #200

IanWhitney opened this issue Sep 11, 2016 · 10 comments

Comments

@IanWhitney
Copy link
Contributor

Initially suggested in #117, we've been adding these stub lib.rs files to most of our recent exercises. I'm still not sold on them, and I wanted to see what other people think.

In the current Maintaining a Language Track document it is suggested that we:

improve the test suites to avoid pushing people towards specific solutions

Which I fully agree with. And I think that stub files also push people towards specific solutions.

Take, for example, Space Age. The test API is generic enough

let duration = Duration::from(1_000_000_000);
Earth::years_during(&duration)

There's more than one way to solve this.

But then the stub file tells students to use Traits. Which they do. I don't think I've seen a solution that removed the Trait.

In Triangle, a possible stub file would be:

pub struct Triangle;

impl Triangle {
    pub fn build(sides: [u16; 3]) -> Result<Self, ()> {
        unimplemented!()
    }

    pub fn is_equilateral(&self) -> bool {
        unimplemented!()
    }

    pub fn is_isosceles(&self) -> bool {
        unimplemented!()
    }

    pub fn is_scalene(&self) -> bool {
        unimplemented!()
    }
}

Which leaves the student with very little to do. The design of the code has already been done. Students are not likely to take this stub and write a solution that uses Enums, Traits or Boxes. Solutions using those approaches are interesting to write and discuss.

@IanWhitney
Copy link
Contributor Author

Summoning @kytrinyx to see if she has thoughts.

@petertseng
Copy link
Member

Looking for that exercise where you consciously decided not to add a stub file... ah, it was #178. It was not for the exact same reason as described in here (here: "it restricts the solution" and in #178 "it reduces learning since coming up with the right signature should be part of the learning process").

In React at #191 I chose to include the stub file since:

  • there are many methods to implement
  • you have to satisfy the compiler on all of the tests before you can get the first one passing!
  • specifying the interface IMO does not restrict the implementation (notice that the Cell from the example solution is not present in the interface at all! Only CellID, and what the reactor does with a CellID when it is passed one for value or set_value is entirely its own business)

In Triangle I was also going to bring up that we might choose not to include a stub file.

So it may sound like a dissatisfying answer, but we may have to decide case by case

But then the stub file tells students to use Traits. Which they do. I don't think I've seen a solution that removed the Trait.

This becomes a little unfortunate - we could instead remove the trait from the stub file and place a years_during on each individual planet, but then maybe it would go the opposite way - students might not think "I can remove all these individual functions by having all the planets implement a trait"

@IanWhitney
Copy link
Contributor Author

Looking back through previous discussions, having a stub file in src/lib.rs addresses 3 problems.

  1. Providing function signatures
  2. Saving people from having to create a src directory and lib.rs file
  3. Allowing the tests to run before the problem is fully solved

Number 1: Can be nice, in some cases, and to proscriptive in others.

Number 2: Eh. People can type mkdir src; touch src/lib.rs or whatever. It's not especially onerous.

Number 3: Huge. Not being able to run tests until you at least have unimplemented!() functions -- with the correct signatures -- for each part of the API is a giant pain.

I don't know of a way to solve the test-running problem without also introducing the problems that come with proscriptive function signatures.

The only option I can think of, and it's not a great one, is to comment out the tests. We'd have to change our CI so that it uncomments the tests before running, though.

@petertseng
Copy link
Member

petertseng commented Sep 11, 2016

I happen to know that the C++ track uses conditional compilation: https://github.com/exercism/xcpp/blob/master/leap/leap_test.cpp#L10

So, maybe we could have the same instead of using ignore? We do have conditional compilation: https://doc.rust-lang.org/book/conditional-compilation.html

But the problem is it may be harder to understand.

@steveklabnik
Copy link
Contributor

steveklabnik commented Sep 11, 2016

I personally prefer including a src/lib.rs that's empty, or, maybe on the one that requires the external crate, adding the extern crate line. It was really, really annoying to have to generate the file upon starting each new exercise, and with an empty file, you still get a compiler error on the first build.

Number 2: Eh. People can type mkdir src; touch src/lib.rs or whatever. It's not especially onerous.

I found it supremely annoying, especially since you can't cargo init . either.

@IanWhitney
Copy link
Contributor Author

Conditional Compilation does solve the main problem I want to solve, yes.

In Cargo.toml

[features]
unimplemented = []
testable = []

In the tests

#[cfg(feature = "unimplemented")]
fn test_a_thing() {
  // test
}

One option would be to have the students replace unimplemented with testable and then run cargo test --features testable. Or they could replace that entire line with #[test] and then run the normal cargo test.

Or maybe there's a better way.

@DuBistKomisch
Copy link

My two cents as someone currently following the track: having to mkdir and touch after fetching every problem gets old very fast and isn't teaching you anything new (after the first time I guess), so it would be nice to at least include an empty src/lib.rs even if no actual stubs. I definitely see value in making people come up with the signatures on their own though.

@kytrinyx
Copy link
Member

kytrinyx commented Jan 2, 2017

having to mkdir and touch after fetching every problem gets old very fast and isn't teaching you anything new

@DuBistKomisch That's a fair point.

it would be nice to at least include an empty src/lib.rs even if no actual stubs

That seems like it could potentially be a good compromise (as long as there's no compile error that would throw CI off).

@ijanos
Copy link
Contributor

ijanos commented Jan 3, 2017

That seems like it could potentially be a good compromise (as long as there's no compile error that would throw CI off).

CI creates/overwrites lib.rs with the example anyways, so no problems there.

@mkantor
Copy link
Contributor

mkantor commented Apr 3, 2017

@IanWhitney why did you close this? Consensus doesn't appear to have been reached and the exercises still contain various approaches when it comes to placeholder src/lib.rs files.

I inadvertently opened a duplicate ticket (#269) because I missed this one. I'll close mine if you think this should be reopened.

petertseng pushed a commit that referenced this issue Apr 3, 2017
See #117, #200, and #269.

Since the jury is still out on whether/how to provide stub functions, I
opted to simply add empty files in this commit. This makes for a
smoother user experience, as students will no longer have to invoke
`mkdir src; touch src/lib.rs` for every exercise.
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

7 participants