sketchucation logo sketchucation
    • Login
    🤑 SketchPlus 1.3 | 44 Tools for $15 until June 20th Buy Now

    How Many Observers?

    Scheduled Pinned Locked Moved Developers' Forum
    9 Posts 3 Posters 1.5k 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.
    • J Offline
      Jim
      last edited by

      Is there any concern about having too many Observers on a model? Will it have an effect on performance at some point?

      Hi

      1 Reply Last reply Reply Quote 0
      • AdamBA Offline
        AdamB
        last edited by

        It has to have an effect given each instance of observer has to be dispatched. I'd be wary of going crazy with them.

        My 0.02 worth.

        Adam

        Developer of LightUp Click for website

        1 Reply Last reply Reply Quote 0
        • R Offline
          RickW
          last edited by

          I've had some concerns about this. For Smustard scripts, I've started creating a few globals containing observer instances, and those globals can have observer actions added to them dynamically. This limits the number of observers to one of each type, and still allows multiple actions to be observed.

          So far, so good. It would be nice if the SketchUp folks would handle this for us, but if we could all agree on a format, we could just get it done.

          RickW
          [www.smustard.com](http://www.smustard.com)

          1 Reply Last reply Reply Quote 0
          • J Offline
            Jim
            last edited by

            @rickw said:

            I've had some concerns about this. For Smustard scripts, I've started creating a few globals containing observer instances, and those globals can have observer actions added to them dynamically. This limits the number of observers to one of each type, and still allows multiple actions to be observed.

            So far, so good. It would be nice if the SketchUp folks would handle this for us, but if we could all agree on a format, we could just get it done.

            I'm with you. One of the reasons I asked was that, for most observers, there need only be one per model. A model really only needs one: AppObserver, DefinitionsObserver, LayersObserver, MaterialsObserver, ModelObserver, PagesObserver, RenderingOptionsObserver, SelectionObserver, ShadowInfoObserver, ToolsObserver, and possibly ViewObserver.

            But I'm not sure the best way to implement them. I have been experimenting with using the Ruby Singleton class.

            
            require "singleton"
            class AppObserver < Sketchup;;AppObserver
              include Singleton
              def onNewModel(*args)
              # ...
              end
            end
            
            

            This ensures there will only be one instance of AppObserver. You can't call "new" on it because new is made private (raises an exception.) You access it by calling "instance" on it.

            
            Sketchup.add_observer(AppObserver.instance)
            # later that day...
            Sketchup.remove_observer(AppObserver.instance)
            
            

            Both the above calls access the one and only instance of AppObserver. It has the advantage of not needing to create a global variable to store it.

            Then, any plugin that wanted to use it could just require it, and start using it.

            
            # Some Plugin
            require "app_observer.rb"
            
            
            
            # app_observer.rb
            require "singleton"
            class AppObserver < Sketchup;;AppObserver
              include Singleton
              def attach
                Sketchup.add_observer self
              end
              def detach
                Sketchup.remove_observer self
              end
            end
            
            unless file_loaded? "app_observer.rb"
              AppObserver.attach
              file_loaded "app_observer.rb"
            end
            
            

            Sorry to go on so long about it. And I still haven't addressed how a plugin might interact with a singleton observer. Thoughts?

            Hi

            1 Reply Last reply Reply Quote 0
            • R Offline
              RickW
              last edited by

              An instance variable (or perhaps a class variable?) would contain an array of commands that are eval-ed in the observer definition. These commands could be added to the observer by other scritps, and the commands would call those scripts when the observer is fired.

              require "singleton"
              class AppObserver < Sketchup;;AppObserver
                @@Commands = []
                include Singleton
                def onNewModel(*args)
                  @@Commands.each{|command| eval command}
                end
                def addCommand(*args)
                  @@Commands<<args if args.class==String
                end
              end
              
              

              I know the 'eval' command gets a bad rap, but if someone is going to trust a script enough to download it, then 'eval' shouldn't be any worry, either, since the whole script gets 'eval'-ed anyway.

              Obviously, the above example is pretty generic. There should probably be class/instance variables for each possible reactor in an observer, so that a script can reference the relevant actions individually. There should also be error-trapping (begin-rescue-end) and all that.

              RickW
              [www.smustard.com](http://www.smustard.com)

              1 Reply Last reply Reply Quote 0
              • R Offline
                RickW
                last edited by

                Another thought: while an AppObserver is model-independent (and is valid for the whole modeling session), all the others are model-dependent, and need to be recreated when a new model is started or a file is opened. Even though the observer instances are themselves still valid, the things they observe are gone, and thus nothing triggers them.

                So, then, what are the ramifications of using a Singleton for model-specific observers?

                RickW
                [www.smustard.com](http://www.smustard.com)

                1 Reply Last reply Reply Quote 0
                • J Offline
                  Jim
                  last edited by

                  I think this is moving in the right direction. I thought of 2 possibilities, one being similar to what you have shown. I don't think eval is what you want. I think the thing to do is use a Proc object, or code block; which you then call, or yield (not sure.) I don't know enough about using Procs, or blocks to know if this is the way to go.

                  But even so, how can you un-add an added command?

                  The second idea leaves all the details up to the plugin. A plugin would register itself to the AppObserver, and then AppObserver would call the onNewModel method of the registered plugin. Example:

                  
                  class AppObserver < Sketchup;;AppObserver
                    @@callees = []
                    include Singleton
                    def register(object)
                      @@callees << object
                    end
                    def onNewModel(*args)
                      @@callees.each{|callee| callee.onNewModel(args) }
                    end
                  end
                  
                  

                  This also makes it easy to remove an object from the AppObserver. So if a plugin would need to only need:

                  
                  # The Ultimate Plugin
                  require "app_observer.rb"
                  
                  class Plugin
                    AppObserver.instance.register(self)
                    def onNewModel
                      # What to do when a new model happens
                    end
                  end
                  
                  

                  Now, this could really slow thing down if someones plugin mis-behaves, and is called before yours. Could, or should Threads be used in a case like this?

                  
                  def onNewModel(*args)
                    @@callees.each{|callee| Thread.new { callee.onNewModel(args) } }
                  end
                  
                  

                  Hi

                  1 Reply Last reply Reply Quote 0
                  • R Offline
                    RickW
                    last edited by

                    I don't know if there are specific advantages to either threads or begin-rescue-end. b-r-e should work fine, calling things in order then moving to the next, even if an error occurs. I suppose that the 'rescue' section could even lock down and block the trouble-causing item from being called the next time the observer is fired.

                    You would probably want b-r-e even with threading...

                    RickW
                    [www.smustard.com](http://www.smustard.com)

                    1 Reply Last reply Reply Quote 0
                    • J Offline
                      Jim
                      last edited by

                      I'm getting back to thinking about a single AppObserver that everyone can (hopefully) agree on and use. I want to focus on how to use this observer over how it is implemented, i.e. its interface. In that vein, what about a simple interface as follows?

                      
                      require 'sketchup'
                      require 'sk/app_observer'
                      
                      module SelectToolAtStartup
                       def self.selectSelectTool
                          Sketchup.send_action "selectSelectionTool;"
                        end
                      end 
                      
                      Sk;;AppObserver.instance.register(;onNewModel) { SelectToolAtStartup.selectSelectTool }
                      Sk;;AppObserver.instance.register(;onOpenModel) { Sketchup.send_action "selectSelectionTool;" }
                      
                      
                      

                      There would be one and only one AppObserver. The Observer transparently attaches itself when a method is registered, and removes itself when all methods have been unregistered.

                      So any plugin which needs an AppObserver only need require it, and register a method.

                      This same type of interface could be used for all the other "single instance" observers available in SketchUp. I'd like to go ahead and code them all up so plugin devs can start using observers, instead of everyone implementing them individually. I think a library of standard observers would greatly enhance a lot of current plugins, and make writing new plugins with advanced features easier and quicker. But being an amateur, I'd like to hear from more experienced devs on the matter.

                      Hi

                      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