Add Flags Attribute concept exercise - #1387
Conversation
|
Hello. Thanks for opening a PR on Exercism 🙂 We ask that all changes to Exercism are discussed on our Community Forum before being opened on GitHub. To enforce this, we automatically close all PRs that are submitted. That doesn't mean your PR is rejected but that we want the initial discussion about it to happen on our forum where a wide range of key contributors across the Exercism ecosystem can weigh in. You can use this link to copy this into a new topic on the forum. If we decide the PR is appropriate, we'll reopen it and continue with it, so please don't delete your local branch. If you're interested in learning more about this auto-responder, please read this blog post. Note: If this PR has been pre-approved, please link back to this PR on the forum thread and a maintainer or staff member will reopen it. |
|
I'm currently away, so I don't have time to review this right now. Regarding your question: I'm positive that we have other exercises that have the same problem. Likely the discriminated unions exercises. Maybe you could check to see if that is referenced somewhere? There might be an exclude list or something. |
Unlike enum cases in C#, discriminated union members cannot reference other members in F#.
| failwith "Please implement this function" | ||
|
|
||
| /// Return a set of human-readable phrases indicating the meaning of the given result value. | ||
| let getStatusPhrases (result: Result<string, PasswordError>) : Set<string> = |
There was a problem hiding this comment.
This is returning a Set, which means that the student has to know about sets. So either it needs to be a prerequisite, or we should use a list here (which is my preference).
| ``` | ||
|
|
||
| Setting a flag can be done with the bitwise OR operator (`|||`); unsetting a flag can be done with a combination of the bitwise AND operator (`&&&`) and the bitwise negation operator (`~~~`). | ||
| While checking flag's state can be done with the bitwise AND operator, one can also use the HasFlag() method. |
There was a problem hiding this comment.
| While checking flag's state can be done with the bitwise AND operator, one can also use the HasFlag() method. | |
| While checking a flag's state can be done with the bitwise AND operator, one can also use the `HasFlag()` method. |
|
|
||
| // Unset the Call flag | ||
| let lessFeatures = features &&& ~~~PhoneFeatures.Call | ||
|
|
||
| lessFeatures.HasFlag(PhoneFeatures.Call) // => false | ||
| lessFeatures.HasFlag(PhoneFeatures.Text) // => true |
There was a problem hiding this comment.
I'd remove this as I feel confident student should be able to figure this out based on the above example and what is in the other introduction text.
| // Unset the Call flag | |
| let lessFeatures = features &&& ~~~PhoneFeatures.Call | |
| lessFeatures.HasFlag(PhoneFeatures.Call) // => false | |
| lessFeatures.HasFlag(PhoneFeatures.Text) // => true |
There was a problem hiding this comment.
I feel that there might be a more idiomatic F# solution here without using mutable. I'll try and come up with one/
|
|
||
| ## 2. Implement the `checkPassword` function | ||
|
|
||
| The `checkPassword` function checks the given password against the aforementioned rules. On failure, it indicates the rule(s) that was/were violated by encapsulating one or more of the `PasswordError` values within the result value. |
There was a problem hiding this comment.
Each sentence should be on a separate line. And maybe we can be slightly more specific on what should be returned?
| The `checkPassword` function checks the given password against the aforementioned rules. On failure, it indicates the rule(s) that was/were violated by encapsulating one or more of the `PasswordError` values within the result value. | |
| The `checkPassword` function checks the given password against the aforementioned rules. | |
| The function should return a `Result` value, where `Ok` is returned when the password satisfies all rules, and an `Error` value when it fails one or more rules. | |
| If multiple rules fail, the `PasswordError` value should represent all those failing rules. |
Or something like that.
|
|
||
| ## 3. Implement the ``getStatusPhrases` function | ||
|
|
||
| The `getStatusPhrases` function returns a set of strings each containing a human-readable phrase corresponding to one of the erorrs in the result returned from `checkPassword`. |
There was a problem hiding this comment.
As mentioned elsewhere, I'd suggest making this a simple list.
| - Must have at least one digit | ||
| - Must have at least one symbol in the set !@#$%^&\* | ||
|
|
||
| Your solution must use a `Result` to encapsulate the success or failure status. |
There was a problem hiding this comment.
These instructions are specific to task 2 (the other tasks don't use results), so should probably be moved to that task (and I've already added some alternative text there).
| | Text = 0b00000010 | ||
| ``` | ||
|
|
||
| A `PhoneFeatures` instance with the value 0b00000011 has both its Call and Text flags set. |
There was a problem hiding this comment.
| A `PhoneFeatures` instance with the value 0b00000011 has both its Call and Text flags set. | |
| A `PhoneFeatures` instance with the value `0b00000011` has both its `Call` and `Text` flags set. |
There was a problem hiding this comment.
It might be worth adding a mention that flags can be set or unset using bitwise operators.
| [<Fact>] | ||
| [<Task(2)>] | ||
| let ``Missing symbol error with twelve mixed-case letters and digits`` () = | ||
| let expected: Result<string, PasswordError> = Error PasswordError.MissingSymbol | ||
| checkPassword "ABCDEF123ghi" |> should equal expected | ||
|
|
||
| [<Fact>] | ||
| [<Task(2)>] | ||
| let ``Missing digit error with twelve mixed-case letters and symbols`` () = | ||
| let expected: Result<string, PasswordError> = Error PasswordError.MissingDigit | ||
| checkPassword "ABCDEF$&*ghi" |> should equal expected |
There was a problem hiding this comment.
I would start with these two tests, as that allows the student to first focus on the error-returning bit, and then build on that to add the flag setting pattern to combine values. In other words: if the student would follow the current order, these tests will likely always pass without having to do any work.
Introduce the Flags Attribute (aka flags-discriminated-union) concept and provide an exercise to teach it. The exercise goal is to use the Flags attribute to build a password checker capable of reporting multiple rule violations in one call.