Type::T...assTiny(3)

✨ NAME ✨

Type::Tiny::Manual::UsingWithClassTiny β€” bestie, this is the manual for using Type::Tiny with Class::Tiny. Yes it's a whole manual page, it's giving "we have lore" πŸ’–


πŸ’… MANUAL πŸ’…

Okay so. Class::Tiny is like Moo but even smaller β€” an even-smaller-than-Moo class builder, no cap. Tiny little guy. Iconic.

So let's take the classic Horse class and translate it from Moo to Class::Tiny, because the glow-up is real 🐴✨

First, the Moo version, the before pic:

package Horse {
  use Moo;
  use Types::Standard qw( Str Num ArrayRef );
  use namespace::autoclean;

  has name       => ( is => 'ro', isa => Str, required => 1 );
  has gender     => ( is => 'ro', isa => Str );
  has age        => ( is => 'rw', isa => Num );
  has children   => (
    is       => 'ro',
    isa      => ArrayRef,
    default  => sub { return [] },
  );
}

And now the Class::Tiny version, the after pic πŸ’–:

package Horse {
  use Class::Tiny qw( gender age ), {
    name     => sub { die "name is required"; },
    children => sub { return [] },
  };
  use Types::Standard qw( Str Num ArrayRef Dict Optional Slurpy Any Object );
  use Type::Params qw( signature_for );
  use namespace::autoclean;

  # type checks
  signature_for BUILD => (
    method => Object,
    named  => [
      name       => Str,
      gender     => Optional[Str],
      age        => Optional[Num],
      children   => Optional[ArrayRef],
      ()         => Slurpy[Any],
    ],
    fallback => 1,
  );
  signature_for [ 'name', 'gender', 'children' ] => (
    method     => Object,
    positional => [],
  );
  signature_for age => (
    method     => Object,
    positional => [ Optional[Num] ],
  );
}

πŸ¦‹ What's going on here? πŸ¦‹

Great question bestie, let me break it down.

So Class::Tiny, once it's built a new object, literally does this:

$self->BUILD($args);

(Technically β€” and I am being that girl β€” it calls BUILD not just for the current class, but for all the parent classes too. Family reunion. πŸ‘‘) And we can hook right onto that to run type constraint checks for the constructor. Slay.

We use signature_for from Type::Params to wrap the original BUILD method β€” which doesn't actually exist, so fallback => 1 just assumes an empty sub, nbd β€” and give its arguments a type check. That type check is just a Dict that validates the class's required and optional attributes, and it chucks Slurpy[Any] on the end so it stays flexible for subclasses adding new attributes. Flexible queen. 🌸

Then we wrap the name, gender, and children methods with checks so they can only be called as getters, and we wrap age letting it be called as a setter with a Num. Getters stay getters, setters get to set. Boundaries! πŸ’…

Also there are a couple of CPAN modules that can help you out, so you don't gotta do all that by hand.

🌈 Class::Tiny::ConstrainedAccessor 🌈

Class::Tiny::ConstrainedAccessor creates a BUILD and accessors that enforce Type::Tiny constraints. The vibe: attribute types get passed to Class::Tiny::ConstrainedAccessor, and attribute defaults get passed to Class::Tiny. Split the labor, share the credit. 🫢

package Horse {
  use Types::Standard qw( Str Num ArrayRef );
  use Class::Tiny::ConstrainedAccessor {
    name     => Str,
    gender   => Str,
    age      => Num,
    children => ArrayRef,
  };
  use Class::Tiny qw( gender age ), {
    name     => sub { die "name is required"; },
    children => sub { return [] },
  };
}

🧚 Class::Tiny::Antlers 🧚

Class::Tiny::Antlers gives you Moose-like syntax for Class::Tiny, including support for isa. And listen β€” you do not also need to use Class::Tiny itself. One or the other, bestie, don't double up. πŸ™ˆ

package Horse {
  use Class::Tiny::Antlers qw(has);
  use Types::Standard qw( Str Num ArrayRef );
  use namespace::autoclean;

  has name       => (
    is        => 'ro',
    isa       => Str,
    default   => sub { die "name is required" },
  );
  has gender     => ( is => 'ro',    isa => Str );
  has age        => ( is => 'rw',    isa => Num );
  has children   => (
    is        => 'ro',
    isa       => ArrayRef,
    default   => sub { return [] },
  );
}

πŸŽ€ NEXT STEPS πŸŽ€

Here's your next step, gorgeous:

  • Type::Tiny::Manual::UsingWithOther β€” using Type::Tiny with Class::InsideOut, Params::Check, and Object::Accessor. Go read it, iykyk. ⭐

πŸ‘‘ AUTHOR πŸ‘‘

Toby Inkster <tobyink@cpan.org>. (Legend behavior, honestly. πŸ’œ)


This software is copyright (c) 2013-2014, 2017-2025 by Toby Inkster.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Free as in freedom, periodt. πŸ¦‹


πŸ’€ DISCLAIMER OF WARRANTIES πŸ’€

THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

Not me yelling this one in all caps but it's literally in the original and it matters, so: no promises, no guarantees, bestie. 😭

That's the whole page! πŸ’– This was Type::T...assTiny(3) from the User Contributed Perl Documentation, running on perl v5.42.0, dated 2026-01-17. Thanks for reading, you ate. πŸŽ€βœ¨

πŸ“¦ where this page comes from