2

In this example code where I have child classes (Bar, Baz) inheriting the class methods of the parent (Foo), how might I ensure @foo is only created once across all children?

class Foo
  def self.foo
    # only want @foo to be set once across any child classes 
    # that may call this inherited method.
    @foo ||= expensive_operation
  end
end

class Bar < Foo
  def self.bar
    self.foo + 'bar'
  end
end

class Baz < Foo
  def self.baz
    self.foo + 'baz'
  end
end
3
  • NB: you are to mark the answer as correct if it helped you. Commented May 9, 2017 at 4:30
  • 1
    It does no harm, but self.foo + 'bar' can be written foo + bar as self is Bar when that is executed. Same for Baz. Commented May 9, 2017 at 4:58
  • This looks like an XY-question. Commented May 9, 2017 at 8:09

2 Answers 2

4

Instead of depending on a class-specific instance variable being present, just reference it directly:

class Baz < Foo
  def self.baz
    Foo.foo + 'baz'
  end
end
Sign up to request clarification or add additional context in comments.

7 Comments

Oh, ok. So I still need to set @foo in self.foo, but the callers need only call Foo.foo? And that will ensure @foo is only set once?
If you call Foo.foo then it's going to ensure that all calls are directed to exactly the same instance. If you call self they're on their own unless you start to share things between class instances, and then it gets messy. This is the most direct approach.
Makes total sense. Thank you kindly.
Just a tiny addendum: “all calls are directed to exactly the same instance” ⇒ namely, to the instance of class Class, named Foo.
@mudasobwa That's a more specific way of putting it which explains it a bit better.
|
0

This is exactly what class instance variable is intended for - language mechanism to have one variable shared between classes which inherit from a class. It's generally not recommended to use because it behaves like you want to - and that's confusing for people coming from other languages.

class Foo
  def self.foo
    # notice @@
    @@foo ||= expensive_operation
  end

  def self.expensive_operation
    puts "Expensive operation"
    "cached value "
  end
end

class Bar < Foo
  def self.bar
    self.foo + 'bar'
  end
end

class Baz < Foo
  def self.baz
    self.foo + 'baz'
  end
end

Foo.foo
Bar.bar
Baz.baz

This prints Expensive operation only once.

8 Comments

Please never use class variables like that, there are many drawbacks.
@mudasobwa - what are the drawbacks?
E.g. try @@foo = "WTF?" immediately before Foo.foo after all the classes are defined.
I get warning: class variable access from toplevel. I'd expect that not to be possible, syntax error. I have no idea how it knows where @@foo is defined, but it's a warning that stops execution of program (nothing gets printed) so it's pretty close.
Warnings do not stop the execution of the program. “Nothing gets printed” because your code does not print anything. Use puts to print anything to $stdout.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.