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

Create mentoring.md for grains exercice in cpp #2339

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

CornierQuentin
Copy link

Creating the guide for the solution of the grains exercise in cpp. Offering an imperative and a recursive solution for the first function and explaining how to do correctly the second function.

Creating the guide for the solution of the grains exercise in cpp. Offering an imperative and a recursive solution for the first function and explaining how to do correctly the second function.
@github-actions github-actions bot added track/cpp C++ track type/mentor-notes Mentor notes labels Apr 7, 2024
Copy link

@siebenschlaefer siebenschlaefer left a comment

Choose a reason for hiding this comment

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

All three functions in this document are implemented with loops or recursion.
That is a valid way to solve the exercise.

But there's a more direct way by calculating the result.
square() can be implemented with 1ULL << (indice - 1) and
total() can be implemented in a variety of ways, e.g.:

return 18'446'744'073'709'551'615;
return 0xFFFF'FFFF'FFFF'FFFF;
return (1ULL << 63) * 2 - 1;
return (1ULL << 32 << 32) - 1;
return (2ULL << 63) - 1;
return UINT64_MAX;
return std::numeric_limits<std::uint64_t>::max();
return ~static_cast<std::uint64_t>(0);
return static_cast<std::uint64_t>(-1);
return std::bitset<64>().set().to_ullong();
return 2 * square(64) - 1;

I'd guess that this direct calculation of the result was one of the ideas behind the exercise. Do you mind including such a direct calculation as well for the two functions?

return result;
}
```
A cleaner way to do this is to use a recursive function :

Choose a reason for hiding this comment

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

I'd argue that it is subjective whether a recursive implementation is "cleaner" than one using a loop.
Personally I prefer the function with the loop, with my imperative mindset I find it a tiny bit easier to understand, and it avoids the overhead of the recursive function call.
If you really want to call it "cleaner" I'd prefer if you make it clear that this is an opinion (like later with the "in my mind".)


The first way to implement this function is to use a for loop :
```cpp
unsigned long long square(int indice) {

Choose a reason for hiding this comment

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

Here and later: "indice" sounds like French or Italian, right? Since everything else is in English how about index?

Copy link
Author

Choose a reason for hiding this comment

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

Yes I'm french, it happens sometimes that I let a french word in my code. I will do this changes thx :)

Changing indice to index
Removing "cleaner" for the recursive method
Adding the direct method for the first function
@CornierQuentin
Copy link
Author

I've removed "cleaner", changed "indice" to "index" and added the direct method. Hope you will like the changes, don't hesitate to ask me for more changes if you need.
I also wanted to ask you if this is a good things to add such documentation and if you like me to add some more ?

@siebenschlaefer
Copy link

Thank you!

The whole documents sounds like its target audience are "students", e.g. it explains bitwise left-shifting with an example. But these mentoring notes are for "mentors" who (ideally) should already have solved the exercise, understand the assignment and solutions, and want to help others improve their solutions.

Mentoring notes typically contain (1) reasonable solutions, (2) common issues that often occur in solutions (i.e. subtle errors or code smells that a mentor might want to look out for), (3) common suggestions that often can improve solutions, and (4) talking points that repeatedly come up in these discussions. (see https://exercism.org/docs/building/product/mentoring-notes)

For example: I've seen many solutions that implement both functions by calling std::pow(). That works for square() (although it involves floating point arithmetic) but (depending on the exact implementation) not always for total() (the conversion from a floating point value to an integer invokes UB if the integer type cannot represent the value after the truncation of the fractional part). There are solutions that pass the tests but are not valid C++ (e.g. https://exercism.org/tracks/cpp/exercises/grains/solutions/Uberlicious).
Or another issue that I've seen from time to time is using the wrong integer type, e.g. unsigned long or (signed) long long. That can work and pass the tests but only on specific platforms or it might have the wrong semantics.
As for talking points: I've had a few discussions with students about performance, and what is the fastest implementation.

If you want to explain the exercise to a "student" you might want to write "approaches" instead. (see https://exercism.org/docs/building/tracks/approaches). Typically they explain language constructs like the operator << or the general idea of a bitwise left-shift. They are also more visible because we have much more "students" than "mentors, you will get a bigger audience.

Hope you will like the changes, don't hesitate to ask me for more changes if you need.

Do you mind adding an implementation with a direct computation for the second function, too?
What are issues that you've seen in multiple solutions and that should be addressed by the student?
What are typical suggestions that helped the students improve their solution?
Are there any talking points, things that came up a few times in your discussion?

And a few tiny nitpicks:

  • You put a space before each colon. IIRC that's correct in French, but in English there's no such space before colons, exclamation marks, question marks, ...
  • You might want to use single(!) backticks around code fragments (such as variable names or keywords like for) that are embedded in a line. The three backticks are for multiple-line code snippets.

I also wanted to ask you if this is a good things to add such documentation and if you like me to add some more ?

We love contributions, especially documentation. If you need any feedback, input, or help feel free to reach out to me or @vaeng on the forum or on Discord.

removing space before colon
adding a direct implementation for total
adding common issues and suggestions section
@CornierQuentin
Copy link
Author

I've done the changes you've asked for. I wasn't sure about the direct implementation because I often see direct implementation with ULLONG_MAX however it's, in my opinion, like cheating and hard coding the solution just a bit cleaner. So, with this point of view, I also add it to the common issues.
I quite new to exercism and I wasn't sure were to write this doc, I think I will, after finishing this one, make more appoaches doc because I'm not quite sure I have the level to explain to mentors directly.

@siebenschlaefer
Copy link

siebenschlaefer commented Sep 9, 2024

@IsaacG Thanks for reminding me. This got lost in my inbox.

I have to admit I'm unsure about this. Do we really want to encourage students to solve this exercise naively, with loops that repeatedly multiply and/or add? Sure, such a solution is not objectively wrong, but in my opinion it does not go beyond translating the instructions directly into C++, there's no discovery or learning experience.

IMHO this exercise aims at a more elaborate or efficient approach, it wants the students to discover the underlying mathematical principles and that the number of grains on a square and on the whole board can be calculated directly, either with exponentiation or with bitwise operations. IIRC back in Exercism-v2 when exercises had tags this was tagged with "bit operations".

I'd appreciate if some of the other experienced mentors or maintainers would weigh in.

@vaeng
Copy link

vaeng commented Sep 9, 2024

I would also go for the "bit" direction as it is the most straightforward way to solve an exercise based on 2^x questions. I might be heavily biased though, as I am wired to binary and haven't been a novice student in a while.

@IsaacG
Copy link
Member

IsaacG commented Sep 9, 2024

I have to admit I'm unsure about this. Do we really want to encourage students to solve this exercise naively, with loops that repeatedly multiply and/or add? Sure, such a solution is not objectively wrong, but in my opinion it does not go beyond translating the instructions directly into C++, there's no discovery or learning experience.

I don't think we want to encourage students to solve things in any particular direction. We want to encourage them to write code, think and explore. The loop approach isn't ideal but it's not wrong. It's good practice either way. I would encourage students to examine the numbers and look for patterns and think about ways to leverage them.

IMHO this exercise aims at a more elaborate or efficient approach, it wants the students to discover the underlying mathematical principles and that the number of grains on a square and on the whole board can be calculated directly, either with exponentiation or with bitwise operations. IIRC back in Exercism-v2 when exercises had tags this was tagged with "bit operations".

Exercism is about programming, not math and finding closed formula solutions for problems. I've seen people solve sum-of-multiples and multiples-of-sums using closed forumulas but I certainly would not expect that of most students. Unless the instructions explicitly call out that students should look for bitwise approaches, I wouldn't push for that very much. On the Python track, I never suggest replacing exponents with bitwise shifts.

@siebenschlaefer
Copy link

I don't think we want to encourage students to solve things in any particular direction.

Are you sure about that? I've seen quite a few mentoring notes that said something like "try to nudge the student towards this ..." or "suggest that they ..." or "direct them towards ...".

[...] I would encourage students to examine the numbers and look for patterns and think about ways to leverage them.

So you do want to guide them towards a less naive solution? I'm with you on that.

Unless the instructions explicitly call out that students should look for bitwise approaches, I wouldn't push for that very much. On the Python track, I never suggest replacing exponents with bitwise shifts.

As I wrote earlier, IMHO exponentiation is fine, too. (But in C++ you have to be careful when using pow() in the function total(), I've seen a lot of solutions with undefined behavior.)

@IsaacG
Copy link
Member

IsaacG commented Sep 11, 2024

I don't think we want to encourage students to solve things in any particular direction.

Are you sure about that? I've seen quite a few mentoring notes that said something like "try to nudge the student towards this ..." or "suggest that they ..." or "direct them towards ...".

I'm sure that's what I think. That doesn't mean all the mentoring notes align with what I think we want.

So you do want to guide them towards a less naive solution?

Yes. I want to guide them to explore and think about less naive solutions. Without being prescriptive and telling them they need to implement any specific solution. If they recognize the pattern and opt not to use it in their solution, I think that's entirely fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
track/cpp C++ track type/mentor-notes Mentor notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants