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

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

by tobyink (Canon)
on Mar 06, 2023 at 14:37 UTC ( [id://11150787]=note: print w/replies, xml ) Need Help??


in reply to Re: Thoughts on new 'class' OO in upcoming perl
in thread Thoughts on new 'class' OO in upcoming perl

For what it's worth, I believe this will work, even without support for :common:

class Foo { field $x :param = 0; field $y :param = 0; } sub Foo::create ( $class, %args ) { if ( $args{x} < 0 ) { return undef; } else { return $class->new( %args ); } } my $foo = Foo->create( x => $x, y => $y ) or do_some_error_handling();

Not the nicest workaround, but also not terrible.

Replies are listed 'Best First'.
Re^3: Thoughts on new 'class' OO in upcoming perl
by cavac (Prior) on Mar 06, 2023 at 14:56 UTC
        Technically correct, but it ignores one little detail: Calling ->new is the normal, default way to create an object. Calling bless directly is not.

        There's quite a difference between expecting people to not instantiate an object in a way which 99% of classes consider to be an unsupported backdoor "here be dragons" approach (bless) and expecting them to not instantiate it in a way which 99% of classes consider to be the standard way to do it (calling the ->new method).

      How would you prevent someone from calling new() directly, in this case skipping your argument checks?

      Actually, this is possible. Your valid constructor methods just create a sufficiently secure random token and pass this to new. Here's a simple example where you can create objects with calls to the valid_constructor function, but not by directly calling new:

      use 5.37.9; use feature 'class'; no warnings 'experimental'; class No::New { use Carp; field $token :param; my %valid_tokens; ADJUST { delete $valid_tokens{$token} or croak "Directly calling ", __PACKAGE__, "->new is forbidden"; } sub valid_constructor { my $token = rand; $valid_tokens{$token} = 1; __PACKAGE__->new(token => $token); } method text { "Congratulations!"; } } say No::New->valid_constructor->text;

      Such a technique, as already mentioned by tobyink, is entirely impossible for bless. Since all "traditional" Perl OO frameworks including Object::Pad are based on blessed references, only core OO can prevent objects like bless \q"Arbitrary junk", Your::Class from happening!

        A slightly neater way:

        use 5.37.9; no warnings qw( experimental ); use feature qw( class defer ); use builtins qw( true false ); class No::New { use Carp; my $allow_construction = false; ADJUST { croak "Directly calling @{[ __PACKAGE__ ]}->new is forbidden" unless $allow_construction; } sub create { my $class = shift; $allow_construction = true; defer { $allow_construction = false }; return $class->new; } method text { "Congratulations!"; } } say No::New->create->text;

        (Note: I haven't actually tried this as the most recent Perl I have installed is 5.37.2.)

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (4)
As of 2025-06-13 20:23 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.