Feature #20202
closedMemoized endless method definitions
Description
I propose introducing a shorthand for memoized endless method definitions:
class Foo
def bar ||= :memoized_value
# It should behave like
def bar = (@bar ||= :memoized_value)
end
Not only is this shorter and (IMO) a natural follow-up for endless method definitions, but it's also a common pattern on Ruby codebases. It's very useful to decompose responsibilities into several objects:
class User
def notifications_enabled? = settings.notifications?
def enable_notifications = (settings.notifications = true)
def disable_notifications = (settings.notifications = false)
private
def settings = @settings ||= Settings.new(self)
end
class User::Settings
attr_writer :notifications
def initialize(user)
@user = user
@notifications = false
end
def notifications? = @notifications
end
u = User.new
u.notifications_enabled? # => false
u.enable_notifications
u.notifications_enabled? # => true
In the example, the settings
method could be rewritten as
def settings ||= Settings.new(self)
Updated by rubyFeedback (robert heiler) 10 months ago
matheusrich wrote:
it's also a common pattern on Ruby codebases
I am not sure it is that common. It is perhaps more common in
rails-specific code. For other regular ruby gems out there,
I don't see that many use endless methods nor memoization
(though admittedly I see more memoization than endless method
definitions; this could perhaps be explained by endless method
definitions being still fairly young, and many gem authors
prefer to not be "too quickly" on the most recent ruby version.
Rubular, for instance, still uses Ruby 2.5.9, oddly enough).
Personally I also find endless method definitions harder to
read; I kind of have to look more to the right side, whereas
in regular ruby code with "def foo; end", the latter being on
the same indent level as "def", I kind of look more towards the
left side, and the bottom area below "def". I am rather used
to seeing "def foo; end", although years ago I actually wanted
to see how ruby code would "feel" when we can omit end, like
in python (but without the mandatory ":").
I did not have endless method in mind when I wanted this, though,
and I kind of adjusted to having to type "end".
For instance:
def settings = @settings ||= Settings.new(self)
def notifications? = @notifications
I find this condensed variant harder to read.
Personally I am also interested in sawa's opinion about
the proposal here, as he recently suggested a shortcut
definition for endless method definitions (e. g. by
omitting "def").
In the example, the settings method could be rewritten as
def settings ||= Settings.new(self)
I kind of understand your point of view there and it would
omit some typing to do, right? So this may just be a different
style of writing ruby code. Personally, though, I am not a
big fan of these condensed one-liner variants.
Updated by matheusrich (Matheus Richard) 10 months ago
I understand why some people might not like endless methods, but I don't think they're purely one-line methods (read @zverok (Victor Shepelev) 's take on this). Also they're already merged, so I guess it's out of topic dicussing that.
I am not sure it is that common. It is perhaps more common in
rails-specific code
I'd argue that using a helper object like that is pretty common even outside Rails code. Sometimes it is done via a macro to delegate, instead of an explicit method like I did.
Personally, though, I am not a
big fan of these condensed one-liner variants.
Then I guess my proposal helps with that? It would be shorter than ever to memoize a method.
def settings ||= Settings.new(self)
Updated by matheusrich (Matheus Richard) 9 months ago
@palkan (Vladimir Dementyev) made it possible to play with what this feature would look like via Ruby Next.
Updated by matz (Yukihiro Matsumoto) 8 months ago
- Status changed from Open to Rejected
I don't accept this proposal for several reasons:
- I don't see significant use-case
- method set for a class should be stable for consistency/understandability
- fragile method set could be bad for object shape and method caching
Matz.