Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Re: Thoughts on new 'class' OO in upcoming perl

by haj (Vicar)
on Mar 06, 2023 at 15:30 UTC ( [id://11150793]=note: print w/replies, xml ) Need Help??


in reply to Thoughts on new 'class' OO in upcoming perl

I have been playing with the new object system and in particular with its playground Object::Pad for some time now, and I'd like to encourage you to do this as well. For many of your points here there are solutions or workarounds. Whether you like them or not is a matter of personal taste, but knowing them helps. Well, and some of your points are just plain wrong.

Abort object creation?

In the new object system it is possible to abort object creation, and in many cases the OO system will do it by itself. Most of that has already been implemented in and popularized by Moose. The idea to have a declaration of constructor parameters instead of writing code for them. I agree that this needs effort to learn the new declarative syntax, and there are subtle differences between the different OO systems.

In your example, a mandatory constructor parameter is missing, and in this case, and the OO system can abort the object creation. The difference is that the OO systems don't return undef (as your example does) but throw an exception.

Of course, if you prefer to return undef in that case, you can have that, too: All you need to know is that stuff you used to write in the body of new now goes into the ADJUST phaser.

Constructor not proper functions?

With the new Object system a new function will be generated for you. But that's all about it. Put simply, the difference is that in the new OO systems new is sort of a bless on steroids, so instead of calling bless in the constructor function of your choice, you now call new.

So, the only downside is that the name new is now occupied by the OO system itself. I am using "named" constructors a lot (they now call Class->new(...) instead of bless(...)), occasionally multiple constructors and also factories. In your factory, you need to change the name to e.g. urlHandler, since new is now taken. That doesn't seem unsurmountable.

Deciding when to call parent constructor?

Ah, here's an area where there are differences between bless-based classes, Moo(se)-style OO systems and the new core OO system. In short: You don't ever call parent constructors in core OO. This is intentional.

Instead, the declarations of the parent classes are evaluated by the auto-generated new-method, and the ADJUST-block of the parent is called, in addition to performing these steps for the current class.

Your example of a subclass setting a field to a fixed value has been discussed in great length in the GitHub discussions on Corinna, in particular issue 77. The length of this discussion should indicate that people are aware that this is a bit of a rough area, but nothing (as someone said on IRC) that an ADJUST block can't fix.

Conclusion

I agree that the core OO system takes away the flexibility of the DIY-objects one can build with bless. However, ignoring Moo* is, well, ignorance. Many lessons from Moo* went into core OO. It is a trade-off between the benefits and restrictions, but you can't get a good view if you ignore the benefits.

The best thing of all: bless isn't going to go away. You can continue to hand-craft your classes, hand-write constructors and accessors for maximum flexibility.

  • Comment on Re: Thoughts on new 'class' OO in upcoming perl

Replies are listed 'Best First'.
Re^2: Thoughts on new 'class' OO in upcoming perl
by cavac (Prior) on Mar 08, 2023 at 17:14 UTC

    Well, and some of your points are just plain wrong.

    That's why i discuss this sort of stuff on PM, instead of ranting about "the unfairness of it all" somewhere else on the internet. I always strive to learn ;-)

    Your example of a subclass setting a field to a fixed value has been discussed in great length in the GitHub discussions on Corinna

    As long as it's a topic that isn't forgotten, i'm happy. If in the end the decision is "we will not allow that", i can live with that and will find ways to integrate "the new way of doing things" in my code.

    Instead, the declarations of the parent classes are evaluated by the auto-generated new-method, and the ADJUST-block of the parent is called

    I assume the ADJUST call order is this:

    1. grandparent
    2. parent
    3. current class

    Correct?

    However, ignoring Moo* is, well, ignorance.

    I didn't ignore Moo* as such. I looked into it (a long long time ago, though). I dimly remember it seemed to have a lot of performance and RAM usage problems, at least for my workloads. And it didn't bring enough benefits for my single-developer projects to make sense.

    Things might have changed. And having a newer OO system integrated into Perl core is a different ballgame altogether.

    But to be fair, i can be a very stubborn, ignorant person sometimes who likes to do some things "the old ways". But if i find some new way that i like more, i'am not unknown to become a preacher of those "new ways of doing things". I haven't yet decided if i will "go class" or "stay bless". But you can take it from the time i've taken to look into it and discuss it here on PM that i think it certainly has peaked my interest in a serious (and good) way. If i thought "class" was rubbish, i would have just ignored it completely ;-)

    PerlMonks XP is useless? Not anymore: XPD - Do more with your PerlMonks XP
      I didn't ignore Moo* as such. I looked into it (a long long time ago, though). I dimly remember it seemed to have a lot of performance and RAM usage problems, at least for my workloads. And it didn't bring enough benefits for my single-developer projects to make sense.

      The asterisk is doing a lot of work there. Moose has always been and continues to be a beast (appropriately enough). That is to say it is big, slow and includes a ton of stuff I will never use - YMMV. OTOH, Moo is much smaller and leaner and I've had success using it without being too disappointed with the performance. However, for me (and this is very much an individual opinion) Class::Tiny hits the sweet spot of enough good stuff to be worth using with minimal (basically immeasurably small) overhead. Combine it with Role::Tiny and you have yourself a modern OO system that's bloat free.

      Half the time I still just use bless and friends. Some of those times the model is standard enough that I should have gone with Class::Tiny from the start and other times the flexibility was a bonus. Horses for courses. But no mooses for me.


      🦛

        «Class::Tiny hits the sweet spot…Combine it with Role::Tiny and you have yourself a modern OO system that's bloat free.»

        I have been whistling this tune for quite a long time now. It is nice that I am not alone. I am convinced that you can go far with this system. Very far and beyond.

        Regards, Karl

        «The Crux of the Biscuit is the Apostrophe»

      I am optimistic that the new Perl core OO will get the deserved amount of discussion, like so many of its precedents on CPAN. No harm in different opinions :)

      Regarding your question about ADJUST call oder: You are correct, it is parent first, child last.

Re^2: Thoughts on new 'class' OO in upcoming perl
by Jenda (Abbot) on Mar 17, 2023 at 21:06 UTC
    Of course, if you prefer to return undef in that case, you can have that, too: All you need to know is that stuff you used to write in the body of new now goes into the ADJUST phaser.

    How? How do you prevent your OO system from throwing in case a mandatory parameter is missing and convince it to return undef instead? How do you convince it to return undef from within an ADJUST whateverscifiweaponyoudecidetocallit?

    Your attribute based constructor abort is very limited and while throwing an exception inside an ADJUST thingie would likely abort the constructor ... after wasting time and resources in the constructors and AJDUST lasers of the parent class(es) ... there doesn't seem to be a way to return undef.

    Your OO system's new doesn't look like bless on steroids. It sounds more like bless overdosed with antidepressants.

    Deciding when to call parent constructor?

    If it's something an ADJUST block can fix SHOW US HOW!

    Jenda
    1984 was supposed to be a warning,
    not a manual!

      How? How do you prevent your OO system from throwing in case a mandatory parameter is missing and convince it to return undef instead?

      Good catch! I mixed up things here. It is definitely not possible to coerce a new method to return undef on failure. If you really want that, you need to write a custom constructor. I often write custom constructors, though mostly for other reasons.

      The new core OO system didn't invent this behavior, though. It is quite common with many OO systems on CPAN: They write a constructor method new for you, according to some declarative syntax. Therefore, new is no longer a "user defined constructor method": It is rather a part of the language on the same level as bless (disregarding the specifics of its medication for now). In none of these OO systems you get a chance to call the parent constructor. They all claim that you don't need to call the parent constructor, and they all have some mechanism to deal with inheritance during construction. For the new core OO system, ADJUST blocks are that mechanism.

      There are differences between the new core OO system and the popular CPAN OO systems, and these affect the construction of objects, in particular in an inheritance hierarchy:

      • Moose (also Moo and Object::Pad) offer a BUILDARGS method to mangle the parameter list provided to new before object creation starts. The new core OO system (like e.g. Dios) does not have this, it only allows a hash-style parameter list. So, you could keep arbitrary constructor APIs when moving from bless-style OO to Moose, but you can not achieve that with core OO. This is the main reason why I write custom constructors these days: I want to have control over my constructor API.
      • Child classes have no access to parent attributes unless there are (public) accessor methods for them. In Moose, you could always access the hash containing all fields, this is now gone. Also, Moose allowed to change a field declaration in a subclass with the has '+field' syntax, neither Object::Pad nor core OO allow this. This is sometimes an obstacle during object construction, and the discussion is still ongoing.

        Child classes have no access to parent attributes unless there are (public) accessor methods for them.

        That does not make any sense to the way i do OO. Often enough, i write a base class which does the basics, like for instance, handling a websocket. Then i subclass this and override the empty methods in the base class i need to handle this specific websocket connection. I would still need access to all the stuff in the base class. Yes, technically, i could write accessors, but the would just bloat the code and make it slower. It wouldn't provide any benefits that i can see.

        In fact, it might be contraproductive to provide public methods to access the internals in some cases. I might want to give the child classes the ability to fiddle with internal settings of the websocket, but not provide the object creator (? i mean the object that called new()) the same kind of access.

        PerlMonks XP is useless? Not anymore: XPD - Do more with your PerlMonks XP

      How do you prevent your OO system from throwing in case a mandatory parameter is missing and convince it to return undef instead?

      How do you prevent bless() from throwing in case a mandatory parameter is missing, and convince it to return undef instead?

      my $data = undef; my $object_or_undef = bless( $data, 'My::Class' );

      (The above will throw an exception.)

      The answer is you don't even try to stop bless bless from throwing. You wrap it in sub new { ... } so you have more control over how bless is called:

      package My::Class { sub new { my ( $class, $data ) = @_; return undef unless ref $data eq 'HASH'; bless $data => $class; } } my $data = undef; my $object_or_undef = My::Class->new( $data );

      Similarly, if you don't want core OO's new to throw an exception when mandatory paramaters are missing, you wrap it in another method.

        bless() is an implementation detail, new() is the agreed upon name of the method you are supposed to call.

        Jenda
        1984 was supposed to be a warning,
        not a manual!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11150793]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (2)
As of 2025-06-22 05:12 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuliAnonymous Monks are no longer allowed to use Super Search, due to an excessive use of this resource by robots.