exercism / problem-specifications

Shared metadata for exercism exercises.
MIT License
326 stars 541 forks source link

Update Reverse string to new format #2363

Closed iHiD closed 8 months ago

siebenschlaefer commented 8 months ago

Oh dear... sigh

For a long time the instructions did not ask to solve the exercise without built-in facilities, and I've mentored literally hundreds of solutions of reverse-string on the C++ track where I encouraged students to use the constructor of std::string or the function std::reverse() from the standard library for the reversal because that leads to short, expressive, readable, idiomatic, and very efficient code. Yesterday I spent several hours writing approaches in preparation for next week's featured exercise, discussing both "manual" and build-in methods to reverse a string.

I think I understand why you added that to the instructions, but from my perspective that makes it a different exercise. Now I'm a little bit frustrated, for two reasons: (1) I really think teaching students to use the standard library and built-in facilities is the right thing, it's part of what makes code idiomatic and it's often harder to learn than the syntax of the language. (2) I wasted a few hours writing these approaches for the C++ version. Shall I really delete them?

BethanyG commented 8 months ago

Feels like there isn't an easy track-wide answer here.

I might rephrase to say "if you language provides 'methods of connivence' like text.reverse or string.reversed(), try solving this problem without them".

But I am with @siebenschlaefer and @meatball133. Simply saying "don't use built-in functionality for reversing strings" is a bit problematic, and will probably lead to non-idiomatic code and/or confusion.

For example, in Python strings are considered a sequence type. There is no str.reverse(). However, there is a generic reversed() that applies to all sequence types (lists, tuples, strings, bytearray, & anything implementing __reversed__). But it returns a reverse iterator -- so has to be unpacked and converted back into a string, or used in a loop where a string is assembled. Allowed? Not allowed?

Foregoing reversed() or even list.reverse() -- it is still next to impossible to do a string reverse cleanly & idiomatically without walking the sequence backwards ([::-1]). Yes - you could use enumerate() + range() for that, but that is not what most Python folx would do. You could argue that bracket notation isn't a built-in method (although it is considered a slice(), and slice() is a built-in).

So maybe it would be better to be more language specific with an addendum? For Python, I'd say "if you can, avoid methods like reversed() and list.reverse()", or "Consider what happens when you use [::-1], and think about other ways you might accomplish this, even if it is a bit unidiomatic."

Or maybe we prompt students to think about the process (and main problems) with reversing strings, and have them think about why the language implements the method(s) they way it does? Things along the line of:

How does your approach change if you need to reverse a Unicode string, or a string as bytes? What might be the considerations for when you need to reverse a large set of strings? Take a look at your languages implementation of strings, and why it may or may not include a string.reverse function or method.

senekor commented 8 months ago

I agree with @siebenschlaefer.

In the real world, strings can almost never be assumed to be ascii and that is the only situation where a home-grown solution can be reasonably simple and correct.

For context, on the Rust track we actually encourage students to use a third-party library to process grapheme clusters, since not even unicode code points correspond to what humans think of as a "character". I speak German, writing a function by hand that correctly reverses Würstchenstand is no small feat. (As opposed to Würstchenstand, which is rather easy. Yes, they are rendered the same.)

I would also add that it's quite valuable to have an exercise that requires students to simply look up the correct function in the standard library. That is a skill that needs to be aquired at first, a fact experienced people can easily overlook.

BNAndras commented 8 months ago

"if you language provides 'methods of connivence' like text.reverse or string.reversed(), try solving this problem without them".

I'd tweak this slightly to "try first solving" to highlight students can in fact use the built-ins but they probably should try working the problem with their own code first. string.reversed() only gives me a high-level sense of what's happening, but if I use it after I tried my own code, I'd probably have more of an appreciation of how string reversing works.

iHiD commented 8 months ago

All good points. Thanks :) I'll remove the bit about not using the built-in functions.

I do think for many tracks that just have string.reverse() equivalents, it's worth telling students not to use it. I don't see any real point in there being an exercise where they literally just call a single built-in function. I might consider tell them about that ("there's a really simple way to do this using the standard lib, which is what you should use in production, but let's use the exercise to learn about some deeper aspects of the language and avoid that function" (etc). The same as I don't think calling Date.leap? is particularly useful. But let's leave that to the individual tracks, rather than it being in Problem Specs.

jiegillet commented 8 months ago

On the Elixir track, we opted not to implement this exercise precisely because it's a built-in function, and there are virtually no alternative methods that are worth spending time on, as a beginner exercise anyway.

We do have leap implemented on the track, and even though Date.leap_year? exists, the problem is a bit different in the sense that you can easily implement a correct solution, and it's worth learning about. When it comes to strings though, the difficulty is vastly different (of course it's still worth learning about in general).

ErikSchierboom commented 8 months ago

On the Elixir track, we opted not to implement this exercise precisely because it's a built-in function, and there are virtually no alternative methods that are worth spending time on, as a beginner exercise anyway.

I think the key observation here is there are virtually no alternative methods that are worth spending time on. Maybe we should recommend tracks forego this exercise when the above holds true. For many tracks though it will still make sense to have this exercise, but maybe for a couple it wouldn't.

ErikSchierboom commented 8 months ago

The PR has been updated. Would you all take another look?

iHiD commented 8 months ago

@ErikSchierboom @siebenschlaefer @BethanyG @senekor @BNAndras @meatball133 Happy with this now? I'd like to get the PRs out today if possible.

ErikSchierboom commented 8 months ago

PRs are being created right now.