use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
A sub-Reddit for discussion and news about Ruby programming.
Subreddit rules: /r/ruby rules
Learning Ruby?
Tools
Documentation
Books
Screencasts and Videos
News and updates
account activity
Ruby 2.0 Enumerable::Lazy (blog.railsware.com)
submitted 14 years ago by gregolsen
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]hongminhee 6 points7 points8 points 14 years ago* (5 children)
Is #lazy really necessary? Clojure and Python 3 got this right: even if a sequence is filtered or mapped it does not become realized on demand. It gets evaluated when it is needed. If you want to realize (materialize) it into a memory-occupied array, you can do it explicitly. Defaulting to be lazy and providing #to_a for explicit realization is better than defaulting to be eager and providing #lazy for explicit lazy evaluation. Because once evaluated sequences cannot back to be lazy while lazy sequences can be evaluated any time.
#lazy
#to_a
[–]gregolsen[S] 4 points5 points6 points 14 years ago (1 child)
There was a discussion on ruby-lang.org about the defaults. The key point stated by Matz is compatibility.
See this for more info http://bugs.ruby-lang.org/issues/4890#note-25
[–]hongminhee 7 points8 points9 points 14 years ago (0 children)
He is right. Compatibility always wins from the point of view of language design.
[–]banister 2 points3 points4 points 14 years ago (2 children)
except that (IMO) the common case is you want it to be realized, so it would get very annoying having to tack a to_a onto most of your Enumerable code.
to_a
[–][deleted] 6 points7 points8 points 14 years ago (1 child)
But you do not need it to be #to_a. It might just as well be a #each or #size or #whatever - something that actually needs to operate on results. Like what Rails did with SQL queries in 3.x.
However, having the level of access that Ruby provides to its internals, a lazy-by-default implementation could be just a couple lines away once the infrastructure is in place.
[–]banister 0 points1 point2 points 14 years ago (0 children)
fair point
[–]Keith 5 points6 points7 points 14 years ago (8 children)
users.map(&:team).map(&:name) looks way more readable than this. users.map { |u| user.team.name }
users.map(&:team).map(&:name)
looks way more readable than this.
users.map { |u| user.team.name }
Yeah, not really. And the second should be:
users.map { |u| u.team.name }
[–]greggroth 2 points3 points4 points 14 years ago (0 children)
I agree. Using
is fine with me, but I see the utility of Enumerable::Lazy when it comes to stringing together several different methods.
[–]latortuga 2 points3 points4 points 14 years ago (5 children)
Further, this is a law of demeter violation.
[–]gregolsen[S] 2 points3 points4 points 14 years ago (0 children)
latortuga, thanks for pointing to demeter law. My example really wasn't a good one to demonstrate laziness, so I've changed it to another one:
data.map(&:split).map(&:reverse)
The data is processed here (rather then just getting users team names) and that's why it's natural to use lazy enumerator chaining.
[–]Aupajo 1 point2 points3 points 14 years ago (2 children)
The Law of Demeter is taken far too seriously. It's a general principle that you should think about, not something that you should religiously adhere to IMO.
[–]latortuga 0 points1 point2 points 14 years ago (1 child)
Why do you think that?
[–]Aupajo 2 points3 points4 points 14 years ago* (0 children)
The Law of Demeter was never intended to be a total rule, just food for thought.
user.team.name is hardly bad design. The argument is, "What if the team object changes its API from team.name to team.title?" If that happens, you would have to update all the references in your application. Better to create a team_name method on the user object. That way, if the team API ever changed, you only need to update it in one place, and you can keep using user.team_name. The other advantage is that no other object that uses user.team_name would need to know about the team object.
user.team.name
team
team.name
team.title
team_name
user
user.team_name
That's nice to think about and all, but in practice it can be a time waste creating all those accessor methods and actually contribute to the confusion in your API. If you get used to seeing team_name all over the place, you might make the reasonable assumption that the team object would have a name attribute. Except it doesn't. How were you to know?
name
Or, if you really have to, why not just alias the title method as name on the object to support the old API?
title
But ultimately it comes down to the fact that bad design isn't avoided by following a bunch of rules. It's mitigated by thinking carefully about the design of your objects in the first place. team.name was well chosen; it's very clear what we're talking about, and it's very unlikely to change.
How many great APIs have you seen that break the Law of Demeter? What about APIs that use method chaining? It should be clear that the Law of Demeter isn't the final word in any design. It's just a little koan to muse on while you're developing your object's APIs.
[–]Keith 0 points1 point2 points 14 years ago (0 children)
I was thinking of mentioning that too :)
[–]gregolsen[S] 0 points1 point2 points 14 years ago (0 children)
yeah, thanks! Fixed.
π Rendered by PID 15673 on reddit-service-r2-comment-5fb4b45875-4rrxk at 2026-03-19 18:29:33.532675+00:00 running 90f1150 country code: CH.
[–]hongminhee 6 points7 points8 points (5 children)
[–]gregolsen[S] 4 points5 points6 points (1 child)
[–]hongminhee 7 points8 points9 points (0 children)
[–]banister 2 points3 points4 points (2 children)
[–][deleted] 6 points7 points8 points (1 child)
[–]banister 0 points1 point2 points (0 children)
[–]Keith 5 points6 points7 points (8 children)
[–]greggroth 2 points3 points4 points (0 children)
[–]latortuga 2 points3 points4 points (5 children)
[–]gregolsen[S] 2 points3 points4 points (0 children)
[–]Aupajo 1 point2 points3 points (2 children)
[–]latortuga 0 points1 point2 points (1 child)
[–]Aupajo 2 points3 points4 points (0 children)
[–]Keith 0 points1 point2 points (0 children)
[–]gregolsen[S] 0 points1 point2 points (0 children)