• Login
sketchucation logo sketchucation
  • Login
ℹ️ GoFundMe | Our friend Gus Robatto needs some help in a challenging time Learn More

How Many Observers?

Scheduled Pinned Locked Moved Developers' Forum
9 Posts 3 Posters 1.5k Views
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 17 Mar 2008, 21:37

    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
    • A Offline
      AdamB
      last edited by 18 Mar 2008, 15:53

      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 18 Mar 2008, 20:00

        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 18 Mar 2008, 21:21

          @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 19 Mar 2008, 17:30

            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 19 Mar 2008, 17:42

              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 19 Mar 2008, 21:06

                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 22 Mar 2008, 19:29

                  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 10 Sept 2008, 23:24

                    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