Project

General

Profile

Actions

Feature #20202

closed

Memoized endless method definitions

Added by matheusrich (Matheus Richard) 4 months ago. Updated about 2 months ago.

Status:
Rejected
Assignee:
-
Target version:
-
[ruby-core:116369]

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) 4 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) 4 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 matz (Yukihiro Matsumoto) about 2 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.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0