curriculum icon indicating copy to clipboard operation
curriculum copied to clipboard

Ruby: Custom Enumerables Project: Add description of relationship between `Enumerable` and `#each`

Open JoshDevHub opened this issue 3 years ago • 1 comments

Complete the following REQUIRED checkboxes:

  • [x] I have thoroughly read and understand The Odin Project Contributing Guide
  • [x] The title of this issue follows the location for request: brief description of request format, e.g. NodeJS course: Add lessons on XYZ

The following checkbox is OPTIONAL:

  • [ ] I would like to be assigned this issue to work on it

1. Description of the Feature Request:

Link to thread in the #suggestions-bugs channel: https://discord.com/channels/505093832157691914/1004082866419937341

I've noticed that a very common point of confusion with this project is not understanding the relationship between Enumerable and the classes that mix it in. I don't think puzzling over this should be the goal of the project (it should be about using blocks), and I also feel like telling the learner to research it risks spoiling solutions for some of the project's problems. If I google "how does ruby enumerable module work", the first hit shows an example of a custom created #map for demonstration purposes, which is giving away answers.

I think the explanation should contain two things:

  1. Mention that modules can use instance methods of classes that they're mixed into. We could show some type of example to demonstrate this. Here's a small dummy example that could maybe work, or for a practical example, we could demonstrate how Comparable uses a class's <=> method. Learners are unlikely to have encountered this kind of module/class interaction before this point, and I think this contributes to the confusion people often have when trying to get started.
  2. Tell users that the above concept describes Enumerable's relationship with objects it's mixed into. It expects the object to define an #each, which it then uses to help implement its own methods. This allows it to adapt to different class's needs regarding iteration. In this project, you will define a #my_each for Array, and then you will rebuild some of the Enumerable methods, relying on Array#my_each to help implement them.

Let me know any other suggestions or feedback. Would be glad to hammer out something more concrete / make a PR if maintainers think this is a good idea.

JoshDevHub avatar Aug 03 '22 20:08 JoshDevHub

This issue is stale because it has had no activity for the last 30 days.

github-actions[bot] avatar Sep 03 '22 02:09 github-actions[bot]

This issue is stale because it has had no activity for the last 30 days.

github-actions[bot] avatar Nov 16 '22 02:11 github-actions[bot]

Hey @JoshDevHub

Apologies for the delay in response. We agree this is an area that needs improvement. Is it something you want to take on which we can support you on?

CouchofTomato avatar Nov 17 '22 10:11 CouchofTomato

Hi @CouchofTomato

This is something I'd like to work on yeah. I might want a little direction for the best approach to take for getting the information across. I know from experience helping people through this exercise in the discord that it can be a tricky subject. I thought I might post a couple of different ideas here in this issue for feedback before making the PR. I should be able to get that done within the next few days if that seems like an okay approach.

And thanks for responding! No worries regarding the delay

JoshDevHub avatar Nov 19 '22 03:11 JoshDevHub

@JoshDevHub

I thought I might post a couple of different ideas here in this issue for feedback before making the PR. I should be able to get that done within the next few days if that seems like an okay approach.

This sounds like a great approach :ok_hand:

ChargrilledChook avatar Nov 19 '22 04:11 ChargrilledChook

Apologies for the slow velocity on this. Been a busy couple of months for me but I'm back around to thinking on this. Will try to post something concrete here this week.

JoshDevHub avatar Jan 09 '23 17:01 JoshDevHub

No stress @JoshDevHub, thanks for the update

ChargrilledChook avatar Jan 11 '23 08:01 ChargrilledChook

Apologies for how long it's taken me on this.

Here's a link to this project's introduction in the curriculum: https://github.com/TheOdinProject/curriculum/blob/main/ruby/advanced_ruby/project_custom_enumerables.md

And a link to the project itself: https://github.com/TheOdinProject/custom_enumerable_project

I think I'd like to propose two changes:

  • So this line in the introduction: You should be very familiar with the Enumerable module that gets mixed into the Array and Hash classes -- From conversations I've had with learners going through this project, I feel like this could be assuming a lot. At this point in the curriculum, learners' experiences with builtin data structures will heavily favor arrays. A lot of the Enumerable methods have overridden implementations in the Array class itself (including every method asked for in the Custom Enumerables project except for inject/reduce). This may mean learners haven't spent much time in the docs for Enumerable. I think it could be a good idea to link to the docs and/or the previous lesson on enumerable methods.

  • I want to introduce a very brief example of the kind of mixin interaction happening with Enumerable. I know in the top post of this issue, I specified Comparable as a potential example to give, but I might think there's more value in keeping it very simple and brief here. I'm definitely open to feedback on this though. So for my concrete idea on this change, I was thinking something like:

    "The Enumerable module works by piggybacking off the #each method defined in the classes it's mixed into. This uses a property of mixins you may not have directly encountered: modules can use instance methods for classes they expect to be mixed into:

    class MyClass
      include Shoutable
    
      def say_hello_world
        "Hello, World"
      end
    end
    
    module Shoutable
      def say_hello_world_loudly
        say_hello_world + "!!!"
      end
    end
    
    puts MyClass.new.say_hello_world_loudly
    #-> "Hello, World!!!"
    

    So even though #say_hello_world isn't defined in the Shout module, it can still use it assuming it's mixed into a class that has it. With that pattern in mind, you will define #my_each inside of Array, and then in Enumerable, you will make use of #my_each to help implement the different enumerable methods. This mirrors the interaction the real Enumerable has with the #each method that's defined in Array, Hash, Range, etc."

It might make more sense to place this 2nd change in the project repo's README -- possibly somewhere in this section: https://github.com/TheOdinProject/custom_enumerable_project/blob/main/README.md?plain=1#L65-L79

Let me know any other thoughts/concerns. I think this is definitely something where it can be easy to confuse or overwhelm learners if it's not done well.

JoshDevHub avatar Jan 30 '23 18:01 JoshDevHub

This issue is stale because it has had no activity for the last 30 days.

github-actions[bot] avatar Mar 22 '23 01:03 github-actions[bot]

I'm going to close this because I think the ideas can more effectively be communicated with completing #23481 -- which is under active development.

JoshDevHub avatar Dec 11 '23 04:12 JoshDevHub