0

Example:

require "fluent/plugin/output"

module Fluent::Plugin
    class Outer < Fluent::Plugin::Output
        @outer_var = "Hello from outer variable"

        class Inner
            def initialize()
                puts "@outer_var", @outer_var # nil
                log.info "Hello from inner initialize" # undefined local variable or method log
                outer_method() # undefined method `outer_method' for #<Outer::Inner:0x00007fd2100452b0> (NoMethodError)
            end
        end # Inner

        def initialize()
            Inner.new()
            log.info "Hello from outer initialize" # works
        end

        def outer_method
            puts "Hello from outer method"
        end

    end # Outer
end # Fluent::Plugin

How can I make the outer variables and methods accessible to the inner class? Example here shows how inner/outer classes are defined but not how outer class may be accessed. I understand that the concept of inner/outer classes don't exists in Ruby, as per this answer. What is the best way use the Inner and Outer class while still being part of the output module.

Dante
  • 537
  • 2
  • 4
  • 18
  • Just an idea (I have not thought through it up to its last consequence): If you make `Outer` a module instead of a class, and inside `Inner` you include this module, perhaps the effect is similar to what you want to achieve. But you will have to close the module and reopen it to allow your class to use it, i.e. kind of: `module Outer; ...; end; module Outer; class Inner; include Outer; end; end;` – user1934428 Jun 23 '22 at 11:28

1 Answers1

7

In Ruby, how can inner class access variables/methods defined in outer class?

Ruby does not have a concept of "inner" or "outer" classes. It sounds like you are coming from a language like BETA, Scala, or Newspeak, but Ruby is not BETA, Scala, or Newspeak. As a general rule, any programming language works exactly how the specification for the programming language says it works, not how the specification for some other programming language says it works. BETA, Scala, and Newspeak have nested classes, but Ruby has not.

In Ruby, you can lexically nest a class definition, but that does not create a nested class. If you nest the definition of a class inside the definition of another class, that does not create any sort of relationship whatsoever between those two classes. None. You cannot "access variables/methods" of one class from the other class because there is no relationship between those two classes you could follow in order to get at those variables/methods.

The only thing a nested class definition does, is namespace the constant defined by the inner class definition to the outer class. That's it. There is no relationship between the two classes, the only relationship is between the constant and the class.

It is just not possible.

The way to create relationships between classes in Ruby is inheritance, not nesting (because there is no nesting). The way to create relationships between objects in Ruby is association, aggregation, or composition, not nesting.

Ruby is flexible enough to implement something that behaves like a "proper" BETA-style inner class. Remember, an inner class is "nested" inside an object instance of the outer class. We can emulate that using an instance variable:

class Outer
  attr_reader :Inner

  def outer_method
    __callee__
  end

  private

  attr_writer :Inner

  def initialize
    self.Inner = Class.new(self.class) do
      def inner_method
        [__callee__, outer_method]
      end
    end
  end
end

outer = Outer.new
inner = outer.Inner.new
p inner.inner_method

Please note that I made the inner class inherit from the outer class: that is the way to do behavior sharing in Ruby. You need to have some form of inheritance or association relationship. The nesting does not create a relationship.

Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
  • _"that does not create a nested class"_ – what _is_ a "nested class"? Is there a language agnostic definition you are referring to? – Stefan Jun 23 '22 at 07:34
  • @Stefan : Not language agnostic, but the [nested classes of Java](https://www.geeksforgeeks.org/nested-classes-java/) seem to be similar to what the OP wants to have, and I have the impression that this concept can be abstracted from a concrete languge, thus becoming _language agnostic_. – user1934428 Jun 23 '22 at 09:09
  • @user1934428 Oracle [says](https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html): _"a static nested class is behaviorally a top-level class that has been nested in another top-level class for packaging convenience"_. To me, that sounds a lot like module namespacing in Ruby. – Stefan Jun 23 '22 at 10:32
  • @Stefan: Interesting point. Acutally I'm not really that knowledgeable in Java and can't say of the two documents, which of them is correct. However, even the Oracle-page you are refering to says: _an inner class is associated with an instance of its enclosing class and has direct access to that object's methods and **fields**_. So, at least non-static nested classes seem to do what we are discussing here. – user1934428 Jun 23 '22 at 11:23
  • 1
    @user1934428 inner classes are something else. I was specifically asking about the _"that does not create a nested class"_ part because Jörg seems to carefully distinguish between a nested class _definition_ and an actual nested class. If defining a class within another class or module doesn't qualify as a (real / actual) "nested class", then what _is_ a nested class? (I'm actually curious, because I always refer to them as "nested classes" and I'd like to know if I'm missing something) – Stefan Jun 23 '22 at 11:55
  • @Stefan: Nested classes were introduced for the first time in BETA, from where they were picked up in some other Scandinavian OO languages (e.g. gBETA) and some languages in the Smalltalk family (Newspeak). They also ended up in Scala. The fundamental feature of a *nested class* is that *the class itself* is nested inside something else (usually, an object instance of the outer class). Think of it this way: you would describe a [Russian Matryoshka Doll](https://wikipedia.org/wiki/Matryoshka_doll) as a "nested doll", right? But if I print out the Wikipedia article on Matryoshka Dolls on two … – Jörg W Mittag Jun 23 '22 at 14:22
  • … sheets of paper, and wrap one into the other, then that is not a nested doll, it is a nested *description* of a doll. Java, unfortunately, confuses this issue, because they refer to nested class *declarations* as "nested classes" whereas they refer to what is *usually* called a "nested class" in BETA, Scala, Newspeak, etc. as "inner classes". Note that I am not alone in nitpicking on this, Gilad Bracha who has experience with BETA, is the designer of Newspeak, but crucially also one of the co-authors of the Java Language Specification, has adamantly maintained multiple times that Java … – Jörg W Mittag Jun 23 '22 at 14:26
  • … does not have "real" nested classes, only a crippled version of it. (His words, not mine.) What does it mean for a "nested" class to be nested in an instance of the enclosing class, then? Well, basically, it means two things: 1) when I have `class A; class B end end; a = A.new`, then I access the nested class as `a.B`, i.e. the class `B` is *nested inside* the *instance* of `A`, and 2) the lookup algorithm(s) take(s) nesting into account (e.g. in Newspeak, the algorithm is "out, then up"). Neither of these two is true in Ruby, and only some of it is true for only some of the constructs … – Jörg W Mittag Jun 23 '22 at 14:29
  • … called "nested class" in Java. (That's another problem with Java: there are several constructs with different behaviors which all fall under the broad descriptor of "nested class", the only thing they have in common is that they are class declarations which are nested in something else. But behaviorally, for example, a an anonymous inner class and a static nested class have nothing to do with each other, even though they are both called nested classes by the JLS, because they are class declarations nested in another class declaration or in a method definition, respectively.) – Jörg W Mittag Jun 23 '22 at 14:32
  • Thanks for the clarification. I might have to give Beta or Newspeak a try in order to truly grasp the difference. – Stefan Jun 23 '22 at 15:19