sketchucation logo sketchucation
    • Login
    ℹ️ Licensed Extensions | FredoBatch, ElevationProfile, FredoSketch, LayOps, MatSim and Pic2Shape will require license from Sept 1st More Info

    Nested classes and scope - a puzzle

    Scheduled Pinned Locked Moved Developers' Forum
    12 Posts 3 Posters 956 Views 3 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • thomthomT Offline
      thomthom
      last edited by

      I ran into a problem which is echoed in this SO question:
      http://stackoverflow.com/questions/9739588/difference-between-class-a-class-b-and-class-ab

      <span class="syntaxdefault"><br /></span><span class="syntaxkeyword">class&nbsp;</span><span class="syntaxdefault">A<br />&nbsp;&nbsp;MESSAGE&nbsp;</span><span class="syntaxkeyword">=&nbsp;</span><span class="syntaxstring">"I'm&nbsp;here!"<br /></span><span class="syntaxdefault">end<br /><br /></span><span class="syntaxcomment">#&nbsp;Scope&nbsp;of&nbsp;Object<br /></span><span class="syntaxkeyword">class&nbsp;</span><span class="syntaxdefault">A</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">B<br />&nbsp;&nbsp;</span><span class="syntaxcomment">#&nbsp;Scope&nbsp;of&nbsp;B<br />&nbsp;&nbsp;</span><span class="syntaxdefault">puts&nbsp;MESSAGE&nbsp;&nbsp;</span><span class="syntaxcomment">#&nbsp;NameError;&nbsp;uninitialized&nbsp;constant&nbsp;A;;B;;MESSAGE<br /></span><span class="syntaxdefault">end<br /><br /></span><span class="syntaxcomment">#&nbsp;Scope&nbsp;of&nbsp;Object<br /></span><span class="syntaxkeyword">class&nbsp;</span><span class="syntaxdefault">A<br />&nbsp;&nbsp;</span><span class="syntaxcomment">#&nbsp;Scope&nbsp;of&nbsp;A<br />&nbsp;&nbsp;</span><span class="syntaxkeyword">class&nbsp;</span><span class="syntaxdefault">B<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="syntaxcomment">#&nbsp;Scope&nbsp;of&nbsp;B<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="syntaxdefault">puts&nbsp;MESSAGE&nbsp;&nbsp;</span><span class="syntaxcomment">#&nbsp;I'm&nbsp;here!<br />&nbsp;&nbsp;</span><span class="syntaxdefault">end<br />end<br /><br /></span>
      

      Why can't A::B access MESSAGE - but defining A then B will let B access MESSAGE?

      I also read the article linked in the SO answer (http://yugui.jp/articles/846) but I cannot make sense of my A::B is different.

      Thomas Thomassen — SketchUp Monkey & Coding addict
      List of my plugins and link to the CookieWare fund

      1 Reply Last reply Reply Quote 0
      • A Offline
        Aerilius
        last edited by

        I've struggled similarly (but with binding and Module.nesting).

        It seems that defining
        class A::B; end
        is not comparable to
        class A class B; end end

        I have not fully understood why (maybe the first case uses A just for namespacing)?

        1 Reply Last reply Reply Quote 0
        • thomthomT Offline
          thomthom
          last edited by

          Nesting.png

          😲 😕

          Thomas Thomassen — SketchUp Monkey & Coding addict
          List of my plugins and link to the CookieWare fund

          1 Reply Last reply Reply Quote 0
          • thomthomT Offline
            thomthom
            last edited by

            What is confusing is that you use A::B to access B regardless of which method was used to define it.

            Thomas Thomassen — SketchUp Monkey & Coding addict
            List of my plugins and link to the CookieWare fund

            1 Reply Last reply Reply Quote 0
            • thomthomT Offline
              thomthom
              last edited by

              Further more:

              <span class="syntaxdefault">module A<br />end<br /><br />module A</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">B<br />end<br /><br />A</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">constants </span><span class="syntaxcomment"># ["B"]<br /><br /></span><span class="syntaxdefault">module A<br />  module C<br />  end<br />end<br /><br />A</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">constants </span><span class="syntaxcomment"># ["C", "B"]<br />&nbsp;</span><span class="syntaxdefault"></span>
              

              So - while A::B is not nested inside A - it creates a constant B inside A. This constant B refer to A::B. ❓ 😕 ❓

              Thomas Thomassen — SketchUp Monkey & Coding addict
              List of my plugins and link to the CookieWare fund

              1 Reply Last reply Reply Quote 0
              • thomthomT Offline
                thomthom
                last edited by

                Reference to self - also asked question on Ruby forum: http://www.ruby-forum.com/topic/4404680#1071549

                Thomas Thomassen — SketchUp Monkey & Coding addict
                List of my plugins and link to the CookieWare fund

                1 Reply Last reply Reply Quote 0
                • Dan RathbunD Offline
                  Dan Rathbun
                  last edited by

                  Yes it does not seem intuitive at first... because we often forget and think of our constant references as the namespaces themselves, but they are not. They are only reference identifiers, that point AT the actual module or class instance objects. These instances can have any number of references of whatever kind (local, global, constant, @var or @@var,) pointing at them, from any number of separate namespaces.

                  module Dan
                  
                    # define a pointer to one of TT's constants
                    @@tt_lib_version = TT_Lib;;VERSION
                  
                    # define a local constant pointer to TT's library module;
                    Lib = TT_Lib
                  
                  end
                  

                  Anyway, I just accept it as some internal C-side Ruby limitation (or design,) and have begin defining properly nested namespaces in my code, at the top of the file, thus:

                  #{# NAMESPACE DEPENDANCIES
                  #
                    module Outer
                      NESTING = Module.nesting()
                      def self.parent()
                        NESTING[1] ? NESTING[1] ; TOPLEVEL_BINDING
                      end # def ;;parent()
                      module Inner
                        NESTING = Module.nesting()
                        def self.parent()
                          NESTING[1] ? NESTING[1] ; TOPLEVEL_BINDING
                        end # def ;;parent()
                        class InnerMost
                          NESTING = Module.nesting()
                          def self.parent()
                            NESTING[1] ? NESTING[1] ; TOPLEVEL_BINDING
                          end # def ;;parent()
                        end # class InnerMost
                      end # module Inner
                    end # module Outer
                  #
                  #}#
                  
                  class Outer;;Inner;;InnerMost
                  
                    # I can now use ;;parent() method here,
                    # or access the proper nesting via NESTING
                  
                  end # class
                  
                  

                  ADD: This works for nesting() issues, I'm not sure with outer constant access tho...

                  I'm not here much anymore.

                  1 Reply Last reply Reply Quote 0
                  • A Offline
                    Aerilius
                    last edited by

                    I did something similar (defining a method "outside") because a nested eval("Module.nesting", TOPLEVEL_BINDING) gave not the result that I wanted.

                    1 Reply Last reply Reply Quote 0
                    • Dan RathbunD Offline
                      Dan Rathbun
                      last edited by

                      The issue of namespace nesting is a side issue to the OP issue of constant access.

                      Back on that issue, there is a nifty solution.

                      So I am assuming, Thomas, that you wish to share constants among your namespaces, be they modules or classes.

                      The solution is a Mixin Module of Constants. (I suggest when you set up mixin libraries, that you separate constants, module/class variables, and methods, into separate "mixin" modules. This way when you include() one, you know what it is that is being made visible within the "mixee" namespace.)

                      Notice the bold, underlined term above: made visible
                      When you include() a mixin module (of constants, in this case,) they are made visible in the namespace into which, they are included.
                      Ruby creates proxy lookups into the actual mixin module.
                      The constants are not actually defined, nor cloned, nor dup'ed into the "mixee" namespace.
                      All namespaces that include that mixin module, are truly sharing the SAME constants.*

                      Example, let us say the file is named "TT/Const.rb":

                      module TT
                      
                        module Const
                          MESSAGE = "I'm here!"
                        end # mixin module Const
                      
                        # add proxy constants to toplevel namespace;
                        include(Const)
                      
                      end # module TT
                      

                      And perhaps in another file:

                      module TT;;SomePlugin
                      
                        class SomeNiftyTool
                      
                          require("TT/Const.rb")
                          include(TT;;Const)
                      
                          def activate()
                            UI.messagebox("Message from TT;;Const is, '#{MESSAGE}'")
                          end
                      
                          # the rest of the tool code
                      
                        end # class SomeNiftyTool
                      
                      end # module TT;;SomePlugin
                      

                      * This fact becomes more important to understand when sharing class/module variables via a mixin module. (Changing their values from ANYWHERE they are included, actually changes them in the common mixin module.)

                      🤓

                      I'm not here much anymore.

                      1 Reply Last reply Reply Quote 0
                      • thomthomT Offline
                        thomthom
                        last edited by

                        @dan rathbun said:

                        So I am assuming, Thomas, that you wish to share constants among your namespaces, be they modules or classes.

                        It was trying to make sense of what I find to be an irregularity. It's even for modules and classes.

                        <span class="syntaxdefault">module&nbsp;TT_Test<br /><br />&nbsp;&nbsp;module&nbsp;Foo<br />&nbsp;&nbsp;&nbsp;&nbsp;CHEESE&nbsp;</span><span class="syntaxkeyword">=&nbsp;</span><span class="syntaxstring">'I&nbsp;am&nbsp;Foo!'<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="syntaxdefault">module&nbsp;Bar<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">prod<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;CHEESE<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">q<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;Module</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">nesting<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">other<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;Biz<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;</span><span class="syntaxcomment">#&nbsp;Bar<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="syntaxdefault">def&nbsp;self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">q<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;Module</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">nesting<br />&nbsp;&nbsp;&nbsp;&nbsp;end<br />&nbsp;&nbsp;end&nbsp;</span><span class="syntaxcomment">#&nbsp;Foo<br /><br /><br /><br /><br />&nbsp;&nbsp;</span><span class="syntaxdefault">module&nbsp;Foo</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Biz<br />&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">prod<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;CHEESE<br />&nbsp;&nbsp;&nbsp;&nbsp;end<br />&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">q<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;Module</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">nesting<br />&nbsp;&nbsp;&nbsp;&nbsp;end<br />&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">other<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;Bar<br />&nbsp;&nbsp;&nbsp;&nbsp;end<br />&nbsp;&nbsp;end&nbsp;</span><span class="syntaxcomment">#&nbsp;Foo<br /><br /></span><span class="syntaxdefault">end&nbsp;</span><span class="syntaxcomment">#&nbsp;TT_Test&nbsp;</span><span class="syntaxdefault"></span>
                        

                        ` TT_Test::Foo::Bar.other
                        TT_Test::Foo::Biz
                        nil

                        TT_Test::Foo::Biz.other
                        Error: #<NameError: c:/nested.rb:36:in other': uninitialized constant TT_Test::Foo::Biz::Bar> c:/nested.rb:36 (eval):36

                        So from one module I can access the sibling-modules/classes - from the other not.

                        The reason I wanted to understand this deviance is that it affects how I organize my code.

                        The mixin method you describe might work - depending. But in some scenarios I might just define the modules/classes differently.

                        Thomas Thomassen — SketchUp Monkey & Coding addict
                        List of my plugins and link to the CookieWare fund

                        1 Reply Last reply Reply Quote 0
                        • Dan RathbunD Offline
                          Dan Rathbun
                          last edited by

                          There is also the const_missing() method, which you could override to do some fancy footwork to walk the nesting to find the parent module, then use const_get() to return the reference.

                          That is if Mac Ruby 1.8.5-p0 has these methods...

                          I just find it easier to never assume a sibling can be "seen", and use fully qualified namespace references if I have to.

                          Sometimes I don't.. like observers. They are easy because we write the constructors, and I always pass the outer namespace in as a parent arg to new().

                          I'm not here much anymore.

                          1 Reply Last reply Reply Quote 0
                          • Dan RathbunD Offline
                            Dan Rathbun
                            last edited by

                            Another solution, IF the outer module does not contain instance methods, is to include it into the inner module:

                            module TT_Test
                            
                              module Foo;;Biz
                                include Foo
                                def self.prod
                                  puts CHEESE
                                end
                                def self.q
                                  p Module.nesting
                                end
                                def self.other
                                  p Bar
                                end
                              end # Biz
                            
                            end # TT_Test 
                            

                            I've seen weirder stuff in the standard Ruby Lib extensions, than that.

                            I'm not here much anymore.

                            1 Reply Last reply Reply Quote 0
                            • 1 / 1
                            • First post
                              Last post
                            Buy SketchPlus
                            Buy SUbD
                            Buy WrapR
                            Buy eBook
                            Buy Modelur
                            Buy Vertex Tools
                            Buy SketchCuisine
                            Buy FormFonts

                            Advertisement