2

Why I not get 'init' string ?

class Dwa
  attr_reader :nazwa

  def initialize()
    puts 'init'
    @nazwa = "dwa"
  end
end

class Dwa #open this same object definition
  def initialize()
    super #or super()
    @nazwa = "trzy"
  end
end

d = Dwa.new
puts "#{d.nazwa}"

I open object again and redefine initialize.

When I run code with non-modified class I print init and dwa

How to modify initialize and still run puts 'init'

I expect:

$ run.rb
init
trzy
mechnicov
  • 12,025
  • 4
  • 33
  • 56
0x3
  • 31
  • 3
  • Not sure what you are actually going for here but technically you can use [`Module#prepend`](https://ruby-doc.org/core-3.1.0/Module.html#method-i-prepend) to facilitate this functionality. – engineersmnky May 22 '23 at 20:46
  • how modyfy initialize() function and not lost prev code? – 0x3 May 22 '23 at 20:49
  • PSA: Empty argument lists can and should be omitted in Ruby in most cases, at least according to most style guides, as in `def initialize` – tadman May 23 '23 at 00:42
  • From the [docs](https://ruby-doc.org/3.2.2/syntax/methods_rdoc.html#label-Overriding): _"When Ruby encounters the `def` keyword, it doesn’t consider it an error if the method already exists: it simply redefines it."_ i.e. the existing methods gets replaced. – Stefan May 23 '23 at 06:03

3 Answers3

3

The main issue is that re-opening Dwa and re-defining initialize will replace the old initialize. Since super only works to reference to the superclass it is useless in this scenario.

To call the old behaviour, you'll have to store the old initialize method somewhere and call it from the new definition. One way to do this would be to use instance_method to grab and store the UnboundMethod inside a variable. Then call it (using bind_call) from the re-definition of initialize.

# re-opening Dwa class
class Dwa
  old_initialize = instance_method(:initialize)

  define_method :initialize do
    old_initialize.bind_call(self)
    @nazwa = "trzy"
  end
end

The reason we use define_method :initialize here, instead of def initialize, is because of the context switch. Using define_method :initialize with a block allows us to access the outer old_initialize variable, which is not possible with def initialize.


Alternatively you could change the class structure/hierarchy and define a new class using Dwa as its superclass instead.

class NewDwa < Dwa
  def initialize
    super
    @nazwa = "trzy"
  end
end
3limin4t0r
  • 19,353
  • 2
  • 31
  • 52
0

Why I not get 'init' string ?

The superclass of Doe is Object. Object#initialize doesn't print anything, therefore you don't get any printout.

How modyfy initialize and still run puts 'init'

def initialize
  print 'init'
  @nazwa = "trzy"
end
Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
0

If you decide to override this method, why don't override it fully and explicitly?

Probably it's the best option

But if you still want some hacks, you can use alias

# original class
class Dwa
  attr_reader :nazwa

  def initialize
   puts 'init'
   @nazwa = "dwa"
  end
end
# overriden class
class Dwa
  alias_method :original_initialize, :initialize

  def initialize
   original_initialize
   @nazwa = "trzy"
  end
end
d = Dwa.new
# will print init

puts d.nazwa
# will print trzy
mechnicov
  • 12,025
  • 4
  • 33
  • 56
  • _"why don't override it fully and explicitly?"_ – what do you mean by that? Can you give an example? – Stefan May 23 '23 at 05:58
  • @Stefan I mean to write new method like in Jörg's answer – mechnicov May 23 '23 at 06:06
  • Oh I see. For a less hacky way you could put it into a module and `prepend` it into the class. (IIRC, not at the computer right now) – Stefan May 23 '23 at 06:09