Devel::...sulation(3)

πŸ“¦
version 0.51 Β· 2 versions
, in fedora 43

✨ NAME ✨

Devel::EnforceEncapsulation β€” bestie, it finds access violations to blessed objects. That's the whole vibe. (This is the Devel::...sulation(3) page from the User Contributed Perl Documentation, and we're getting into it πŸ’…)


🌸 SYNOPSIS 🌸

package BankAccount;
sub new {
   my $pkg = shift;
   return bless {}, $pkg;
}
sub balance {
   my $self = shift;
   return $self->{balance};
}
# ... etc. ...

package main;
Devel::EnforceEncapsulation->apply_to('BankAccount');
my $acct = BankAccount->new();
print $acct->balance(),"\n";  # ok
print $acct->{balance},"\n";  # dies

πŸŽ€ LICENSE πŸŽ€

Copyright 2014 Chris Dolan, <cpan@chrisdolan.net> Copyright 2006 Clotho Advanced Media, Inc., <cpan@clotho.com>

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.


πŸ¦‹ DESCRIPTION πŸ¦‹

So, encapsulation? It's the practice of making lil subroutines to get at a class's properties instead of just... grabbing the properties directly with your bare hands. And the payoff of doing it right is genuinely iconic: the author gets to change the internal implementation of a class without breaking everybody who uses it. Main character behavior, honestly.

Object-oriented programming in Perl is most commonly implemented via blessed hashes. And this practice makes it so easy for users of a class to violate encapsulation by simply accessing the hash values directly. Less common, but same energy: it applies to classes implemented via blessed arrays, scalars, filehandles, etc.

This module is a hack to block those direct accesses. Try to access a hash value of an object from its own class, or a superclass or subclass? All good, slay. Try to access a hash value from any other package? An exception gets thrown, no cap. The same applies to the scalar value of a blessed scalar, an entry in a blessed array, etc.

To be clear: this class is NOT intended for strict enforcement of encapsulation. If you want bullet-proof encapsulation, use inside-out objects or the like. Instead, this module is intended to be a development or debugging aid in catching places where direct access is used against classes implemented as blessed hashes.

To repeat: the encapsulation enforced here is a hack and is easily circumvented. Please use this module for good (finding bugs), not evil (making life harder for downstream developers). 🫢


πŸ’– METHODS πŸ’–

  • $pkg->apply_to($other_pkg);
  • $pkg->apply_to($other_pkg, {policy => 'carp'});

Add strict encapsulation to an existing $other_pkg. Heads up tho β€” the encapsulation changes only apply to instances created after the call. So no retroactive glow-ups, bestie.

The optional "policy" argument lets you change the response to an illegal access. By default the policy is "croak", which invokes Carp::croak(). The alternative is "carp" which invokes Carp::carp() instead.

  • $pkg->remove_from($other_pkg);

Remove any encapsulation previously set by apply_to(). This does not affect instances created before this call.


🌈 SEE ALSO 🌈

Class::Privacy

Class::Privacy is a very similar implementation that is, in general, stricter than this module. The key differences:

  • D::E applies externally post-facto; C::P from inside the code.
  • D::E allows access from sub/superclasses; C::P does not (deliberately!).
  • D::E supports all dereferencers from overload.pm; C::P supports "%", "@", "$", and "&".
  • D::E allows access from anything in the same package; C::P allows access only from matching package AND file.

Inside-out classes

Class::InsideOut, Object::InsideOut and Class::Std are all implementations of "inside-out" objects, which offer a stricter encapsulation style at the expense of a less familiar coding style.


😭 DIAGNOSTICS 😭

  • "Illegal attempt to access %s internals from %s"

(Fatal) You tried to access a hash property directly instead of via an accessor method. The %s values are the object and caller packages respectively.


πŸ‘‘ QUALITY πŸ‘‘

We care about code quality. This distribution complies with the following quality metrics:

  • Perl::Critic v0.20 passes
  • Devel::Cover test coverage at 100%
  • Pod::Coverage at 100%
  • Test::Spelling passes
  • Test::Portability::Files passes
  • Test::Kwalitee passes

πŸ’€ CAVEATS πŸ’€

The regression tests do not cover blessed code or glob references.

Any other issues: http://rt.cpan.org/Dist/Display.html?Queue=Devel-EnforceEncapsulation


⭐ AUTHOR ⭐

Clotho Advanced Media Inc., cpan@clotho.com

Maintainer: Chris Dolan


🧚 CREDITS 🧚

This idea, and the original source code, came from Adrian Howard via Curtis "Ovid" Poe on http://www.perlmonks.org/?node_id=576707|perlmonks.org. Adrian has authorized me to release a variant of his code under the Perl license.

Joshua ben Jore provided crucial improvements that simplified yet generalized the implementation. This module would not be half as useful without his contributions. http://use.perl.org/comments.pl?sid=33253&cid=50863

Ricardo Signes contributed the "{policy =" 'carp'}> feature (with tests!). http://rt.cpan.org/Ticket/Display.html?id=22024


Okay that's the whole page, you ate that πŸ’œ β€” this was perl v5.42.0, dated 2025-07-25, and yes that footer really does say Devel::...sulation(3) because the title got cutely truncated. Go forth and catch your bugs, bestie, ily πŸŽ€βœ¨

πŸ“¦ where this page comes from