http://www.perlmonks.org?node_id=830599


in reply to Re: scripting frameworks - a cursory glance
in thread scripting frameworks - a cursory glance

There are no "conflicts between application slots and command slots." Application objects and command objects can share state using the cache.
Yes, but the cache is a component of the application object. And the command object should access application object components via  $self->app->cache not the current way $self->cache

Replies are listed 'Best First'.
Re^3: scripting frameworks - a cursory glance
by krazyk (Beadle) on Mar 25, 2010 at 15:52 UTC
    You are mistaken. The cache object accessible by $self->cache() (where $self is the Command) is the same cache used by the application (and your suggested $self->app->cache() would, if it were supported, do exactly the same thing -- access the cache shared by both the Application and the Command). Once again, the cache is shared state. It is not a "component" of the Application, but rather an instance variable (a reference to the Cache object) kept in both Application and Command.

    It would make no sense for "application object components" to be accessed via the cache (regardless of the syntax used to access the cache). The cache stores whatever a user wants to share (like a logging or a database object), not internal CLI::Framework data.

    If you're reading the code, then yes, the Cache class happens to be implemented inside the Application module (mainly because the existing Cache class is trivially simple and may later be replaced by a more powerful caching system like CHI; I decided it is unworthy of its own module at this stage). But that doesn't make it a "component" of the Application class.

      Furthermore, in a pure OO language like Smalltalk, you wouldnt be able to implement the relation between Application and Command that you have.

      Finally, what happens when each command needs a cache in addition to the application-wide cache? It can no longer have a local cache via $self->cache because the Application decided for the Command what names it would use within its own object.


        First, please take a look at one of the sample apps, showing how Applications and Commands are related and how they share data using a cache. Specifically, look at the Application's init() method and the run() methods in the commands.

        You're right it wouldnt. That was a mis-wording. But: the command object should access application object resources via $self->app->$resource not the current way $self->$resource where $resource might be a slot in the application object or a slot in the command object.

        It sounds like you are misunderstanding the conceptual relationship between Commands and Applications. Commands, in general, are not supposed to access Application object resources because Commands are usually to remain decoupled from Applications entirely. Commands could conceivably be used outside of an Application. There are exceptions, and for those relatively uncommon cases, the Metacommand is provided (see an example of a Metacommand in use).

        The obviously-evil $self->$resource (where $self is a Command and $resource is a slot in the application object) is certainly not allowed. For Metacommands, access to Application object resources is supported exactly the way you endorse (though with slightly different syntax $self->get_app->$resource).

        And: the cache is a resource that the command requires the application to implement and provide. You mentioned uploading Commands to CPAN separately. What sort of interface should a command have with the application? Should the application boldly and indiscriminately put any numbers of slots in the command? Or should there be one well-defined interface via one method between command and object, namely $self->app

        I agree; that's what the cache provides -- one well-defined interface (albeit using two methods instead of one): Cache interface. The commands should (and must) always use that interface. The Application will only interact with the command using this mechanism...

        This code (in CLI::Framework::Application):

        # Share session data with command... # (init() method may have populat +ed # global session data in cache # for use by all commands) $command->se +t_cache( # $app->cache );
        Should raise a red flag, because over time as various commands require various application-level resources, you are going to have to manually keep coding the wedding between application and object here with additional slot injection instead of one well-defined interface via one method between command and object, namely $self->app

        No. Here, I'm sharing ALL session data with the command. The cache is NOT one example of potentially many future resources. It is a container for all resources that will ever be shared between the application and its commands.

        Any given Application will set shared data in the cache (during init(), for example) and the Application will automatically pass on a reference to the cache so the Command has access to it (without requiring that the Command be strongly-coupled to the Application).

        n-fold fanout Just think of what you're doing... let's just say there are 3, as you put it, "instance variables kept in both Application and Command. ", cache1, db_handle, interprocess_communication. Now, you have 4 commands. With your approach, you install all 3 of these accessors in all 4 commands, for a total of 12 accessors for sharing data between application and command. With my approach, only the app accessor is shared between application and command, for a total of 4 accessors. As the number of shared resources grow, your "accessor bloat" grows linearly. My "bloat" is constant at 1.

        Wrong. You've mis-quoted me here. I said "...an instance variable (a reference to the Cache object) [is] kept in both Application and Command." Once again, that Cache object is a single container for all shared data. Keeping a single reference in the Application and Command objects and providing access to it via one accessor in each superclass is quite a bit different than keeping numerous accessors in every single command subclass.

        Because all shared data is managed via the Cache and all commands implement a common interface to the Cache (by virtue of inheritance from CLI::Framework::Command), there is no "accessor bloat" -- the only accessor related to shared data is the one documented here: cache accessor in Command class.

        Finally, what happens when each command needs a cache in addition to the application-wide cache? It can no longer have a local cache via $self->cache because the Application decided for the Command what names it would use within its own object.

        No, CLI::Framework::Command defines an interface that includes the set_cache() method, which is used by the Application. If some future command needs a private cache for some reason, there's no reason it could not implement one. Sure, it couldn't use the method names in its parent class, but that's an elementary namespace issue, an intrinsic property of object inheritance.

        I believe all of these things are explained in the docs. If not, I'd gladly accept suggestions on how to clarify. I think that the reason for the disconnect is on both ends -- it's tough to explain all these details and it takes patience to read the explanations. C'est la vie.

      It would make no sense for "application object components" to be accessed via the cache (regardless of the syntax used to access the cache).
      You're right it wouldnt. That was a mis-wording. But: the command object should access application object resources via $self->app->$resource not the current way $self->$resource where $resource might be a slot in the application object or a slot in the command object.

      And: the cache is a resource that the command requires the application to implement and provide. You mentioned uploading Commands to CPAN separately. What sort of interface should a command have with the application? Should the application boldly and indiscriminately put any numbers of slots in the command? Or should there be one well-defined interface via one method between command and object, namely $self->app

      This code (in CLI::Framework::Application):

      # Share session data with command... # (init() method may have populated global session data in cache # for use by all commands) $command->set_cache( $app->cache );
      Should raise a red flag, because over time as various commands require various application-level resources, you are going to have to manually keep coding the wedding between application and object here with additional slot injection instead of one well-defined interface via one method between command and object, namely $self->app

      n-fold fanout

      Just think of what you're doing... let's just say there are 3, as you put it, "instance variables kept in both Application and Command. ", cache1, db_handle, interprocess_communication. Now, you have 4 commands. With your approach, you install all 3 of these accessors in all 4 commands, for a total of 12 accessors for sharing data between application and command.

      With my approach, only the app accessor is shared between application and command, for a total of 4 accessors. As the number of shared resources grow, your "accessor bloat" grows linearly. My "bloat" is constant at 1.