karlgoethebier has asked for the wisdom of the Perl Monks concerning the following question:

Hi all, recently tobyink wrote:

«"Classes are just packages" pre-supposes a class-based paradigm...I want to put less emphasis on classes and more on objects. It's possible to create objects by composing roles on-the-fly, for example.»

I guess this is what the method apply_roles_to_object from Role::Tiny is made for.

When would you use (or prefer) it? I can't imagine that this is just a matter of taste or personal preferences.

Thanks for enlightenment in advance and best regards, Karl

«The Crux of the Biscuit is the Apostrophe»

perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

Replies are listed 'Best First'.
Re: Role::Tiny: When to use apply_roles_to_object?
by LanX (Saint) on May 02, 2019 at 16:52 UTC
    From Object-oriented_programming#Criticism

    > The problem with object-oriented languages is they've got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle

    or

    > Furthermore, he cites an instance of a Java professor whose "idiomatic" solution to a problem was to create six new classes, rather than to simply use a lookup table.

    Classes are templates defining behavior (methods) for object instances belonging to that "type". The "constructed" objects are usually restricted to hold data (attributes).

    Sometimes you just need flexible objects having a variety of behaviors which can't be easily typed.

    For instance (let's objectify a $woman ;-) ...

    metaphor

    I always say: My father is German and my mother is complicated.

    The truth is she has three passports, a college degree from a 4th country and speaks 3+ languages. I.e. I can't "type" her anymore.

    So I'd rather avoid this discussion, before my food gets cold. And it's annoying to finally point out that people don't have the necessary background to understand. (that is their (stereo)type system sucks)

    So creating a singleton "class" for every combination of attributes and functions an object could have is expensive, especially in Perl where you have to represent classes in a global hierarchy::of::packages

    It's easier to add methods to an object without the need of typing.

    Self or JS are classless, a JS object inherits from another JS object.

    But that's also bit one dimensional. *

    There are good reasons for OOP like encapsulation or polymorphism, but you could easily be trapped in design hell if you have to maintain an overly complicated class hierarchy, especially because people often can't even agree on the terminology.

    another quote:

    > Paul Graham has suggested that OOP's popularity within large companies is due to "large (and frequently changing) groups of mediocre programmers". According to Graham, the discipline imposed by OOP prevents any one programmer from "doing too much damage"

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

    update

    *) you can also add methods on the fly to an object in JS. object.my_sub = function (...) { ... this.bla ...};

    °) Well, she may be a class of her own but she's not my type.

      Very nice explanation. I have overlooked the "relation to JS" 😎. Thanks and best regards, Karl

      «The Crux of the Biscuit is the Apostrophe»

      perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

Re: Role::Tiny: When to use apply_roles_to_object?
by 1nickt (Canon) on May 02, 2019 at 16:39 UTC

    Hi kgb,

    I use that function in two ways.

    1. When building an object that needs to consume one of a selection of Roles depending on some run-time state, I often have a line that constructs the name of the Role and then composes it into the object with apply_roles_to_object.
    2. When testing a Role, it's often easier or more direct to make a simple object and compose the Role into it, as Toby said, versus having your entire framework fire up to create an object instance, eg when that might imply unrelated DB connections or whatever.

    For example:

    use Test::Most 'die'; use Role::Tiny; package MyClass { # standing in for the real consumer of the role, # which is expensive to instantiate in some way ... use Moo; }; package MyRole { use Moo::Role; sub foo { 42 } }; subtest 'Applying' => sub { my $o = MyClass->new; is( ref $o, 'MyClass', 'object instantiated' ); ok( Role::Tiny->apply_roles_to_object($o, 'MyRole'), 'role applied +' ); is( $o->foo, 42, 'method in Role works!' ); }; done_testing;

    Hope this helps!


    The way forward always starts with a minimal test.

      It really helps. Thank you and best regards, Karl

      «The Crux of the Biscuit is the Apostrophe»

      perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

Re: Role::Tiny: When to use apply_roles_to_object?
by Fletch (Bishop) on May 02, 2019 at 16:26 UTC

    Not an outright answer but the example that comes to mind (vaguely from when I actually skimmed about it aeons ago when dinosaurs still roamed the earth) was the Self language (see Self_(programming_language); also this SO thread looks to have some good pointers (and discussion WRT to JavaScript which has similar prototype inheritance features)).

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

      "...aeons ago...JavaScript which has similar prototype inheritance features"

      Do'h!. It's a matter of taste after all. I repressed my JavaScript experience. Or may be i never got a proper understanding of the language.

      Thanks and best regards, Karl

      «The Crux of the Biscuit is the Apostrophe»

      perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

Re: Role::Tiny: When to use apply_roles_to_object?
by tobyink (Canon) on May 03, 2019 at 16:22 UTC

    One example might be you have a Backend class where your app sends all its data. You might instantiate the backend object like this:

    my $backend = Backend->new(); Role::Tiny->apply_roles_to_object( $backend, qw( Backend::Storage::PostgreSQL Backend::Log::Debug Backend::Interf +ace::TCP ), );

    And now your backend object will store its data in PostgreSQL, and spit out debugging information to its log file, and listen on a TCP port for instructions.

    If you have eight different possibilities for storage (different types of database, XML files, JSON files, etc), 4 different options for logging, and 4 different interfaces (TCP, Unix Sockets, Command Line, and HTTP), that gives 128 possible combinations. You don't really want to have to create classes for Backend::PostgreSQL_Debugging_TCP, Backend::MySQL_Debugging_TCP, Backend::PostgreSQL_Debugging_HTTP, etc. Instead you just compose the combination of roles you want.

    (In this particular example, there's an argument for making more use of delegation instead of composition, but I digress.)

      > In this particular example, there's an argument for making more use of delegation instead of composition

      actually I also had rather delegation in mind when answering this question.

      As far as I understood does Role::Tiny -> apply_roles_to_object() actually create a new anonymous package and is reblessing the object. °

      IMHO delegation sounds like a better approach, unless the performance penalty of the extra forwarding sub matters.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

      °) quote "Object is reblessed into the resulting class."

        That's how it works, but should be considered an internal implementation detail.

        Delegation is probably a better approach for the example I used earlier, but it requires the base class to have prior knowledge of the kinds of "plugin functionality" that will be added to it, so that it knows when to delegate to them. In many cases, the base class won't have prior knowledge.

        "does Role::Tiny -> apply_roles_to_object() actually create a new anonymous package and is reblessing the object"

        That's a feature.

        use strict; use warnings; use feature 'say'; use Role::Tiny; package MyClass { use Moo }; package MyRole { use Moo::Role }; my $o = MyClass->new; Role::Tiny->apply_roles_to_object($o, 'MyRole'); say ref($o);
        Output:
        MyClass__WITH__MyRole


        The way forward always starts with a minimal test.

      Thank you. Best regards, Karl

      «The Crux of the Biscuit is the Apostrophe»

      perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help