Types::CLike - C-like data types for Moo(se)


    package MyPackage;
    use Moo;  # or Moose or Mouse
    use Types::CLike qw(:c);
    has 'foo' => (
       isa => Int     # or Int32, Signed32
    has 'bar' => (
       isa => Short   # or SmallInt, Int16, Signed16
    use Scalar::Util qw(blessed);
    use Math::BigFloat;
    use Sub::Quote;
    has 'baz' => (
       isa => Double,  # or Float64, Binary64
       # A Double number gets pretty big, so make sure we use big numbers
       coerce => quote_sub q{
             unless (blessed $_[0] =~ /^Math::BigFloat|^bignum/);


Given the popularity of various byte-sized data types in C-based languages, databases, and computers in general, there's a need for validating those data types in Perl & Moo(se). This module covers the gamut of the various number and character types in all of those forms.

The number types will validate that the number falls within the right bit length, that unsigned numbers do not go below zero, and "Perl unsafe" numbers are blessed. Blessed numbers are also checked to make sure they have an accuracy that supports the right number of significant decimal digits. (However, BigInt/Float defaults to 40 digits, which is above the 39 digits for 128-bit numbers, so you should be safe.)

Char types will validate that it's a single character, using Perl's Unicode-complaint length function. The bit check types will also check that the ASCII/Unicode code (ord) is the right bit length.

IEEE 754 decimal floating types are also available, which are floats that use a base-10 mantissa. And the SQL Server "money" types, which are basically decimal numbers stored as integers.


All available types (including lots of aliases) are listed below:

    ### Integers ###
              [SIGNED]                                   | [UNSIGNED]
      4-bit = SNibble SSemiOctet Int4 Signed4            | Nibble SemiOctet UInt4 Unsigned4
      8-bit = SByte SOctet TinyInt Int8 Signed8          | Byte Octet UnsignedTinyInt UInt8 Unsigned8
     16-bit = Short SmallInt Int16 Signed16              | UShort UnsignedSmallInt UInt16 Unsigned16
     24-bit = MediumInt Int24 Signed24                   | UnsignedMediumInt UInt24 Unsigned24
     32-bit = Int Int32 Signed32                         | UInt UnsignedInt UInt32 Unsigned32
     64-bit = Long LongLong BigInt Int64 Signed64        | ULong ULongLong UnsignedBigInt UInt64 Unsigned64
    128-bit = SOctaWord SDoubleQuadWord Int128 Signed128 | OctaWord DoubleQuadWord UInt128 Unsigned128
    ### Floats (binary) ###
    (Total, Exponent) bits; Significand precision = Total - Exponent - 1 (sign bit)
    ( 16,  4) bits = ShortFloat
    ( 16,  5) bits = Half Float16 Binary16
    ( 32,  8) bits = Single Real Float Float32 Binary32
    ( 40,  8) bits = ExtendedSingle Float40
    ( 64, 11) bits = Double Float64 Binary64
    ( 80, 15) bits = ExtendedDouble Float80
    (104,  8) bits = Decimal    # not a IEEE 754 decimal, but C#'s bizarre "128-bit" float
    (128, 15) bits = Quadruple Quad Float128 Binary128
    ### Floats (decimal) ###
    (Digits, Exponent Max)
    ( 7,   96) = Decimal32
    (16,  384) = Decimal64
    (34, 6144) = Decimal128
    ### "Money" ###
    (Bits, Scale)
    ( 32,  4) = SmallMoney
    ( 64,  4) = Money Currency
    (128,  6) = BigMoney  # doesn't exist; might change if it does suddenly exists
    ### Chars ###
    Bit check types = Char/Char8, Char16, Char32, Char48, Char64


Since there are so many different aliases in this module, using :all (while available) probably isn't a good idea. So, there are some Exporter tags available, grouped by language:

    # NOTE: Some extra types are included to fill in the gaps for signed vs. unsigned and
    # byte vs. char.
    :c       = Char Byte Short UShort Int UInt Long ULong Float Double ExtendedDouble
    :stdint  = Int4 UInt4 ... Int128 UInt128 (except 24-bit)
    :c#      = SByte Byte Char16 Short UShort Int UInt Long ULong Float Double Decimal
    :ieee754 = Binary16,32,64,128 and Decimal32,64,128
    :tsql    = TinyInt SmallInt Int BigInt SmallMoney Money Float64 Real
    :mysql   = TinyInt SmallInt MediumInt Int BigInt (and Unsigned versions) Float Double
    :ansisql = SmallInt Int Float Real Double
    :is_*     = All of the is_* functions for that tag
    :to_*     = Same for to_* functions
    :assert_* = Same for assert_* functions
    :+*       = Imports is_*, to_*, assert_*, and types for that tag



All of these types are basically aliases of parameterized types in Types::Numbers. Caveats of those types apply here. The types used are as follows:

    SignedInt     # signed integers
    UnsignedInt   # unsigned integers
    FloatBinary   # binary floats
    FloatDecimal  # decimal floats
    FixedBinary   # money types
    Char          # char types

Type namespace conflicts

Some types are also used by Types::Standard and Types::Numbers, namely Int and Char. So be careful not to import them at the same time, as they have different meanings.

Differences between CLike and real data types

Most C-based languages use a char type to indicate both an 8-bit number and a single character, as all strings in those languages are represented as a series of character codes. Perl, as a dynamic language, has a single scalar to represent both strings and numbers. Thus, to separate the validation of the two, the term Byte or Octet means the numeric 8-bit types, and the term Char means the single character string types.

The term long in C/C++ is ambiguous depending on the bits of the OS: 32-bits for 32-bit OSs and 64-bits for 64-bit OSs. Since the 64-bit version makes more sense (ie: short < int < long), that is the designation chosen. To avoid confusion, you can just use LongLong and ULongLong.

The confusion is even worse for float types, with the long modifier sometimes meaning absolutely nothing in certain hardware platforms. Long isn't even used in this module for those types, in favor of IEEE 754's "Extended" keyword.


The floats will support infinity and NaN, since C floats support this. This may not be desirable, so you might want to subtype the float and test for Inf/NaN if you don't want these. Furthermore, the "Perl safe" scalar tests for floats include checks to make sure it supports Inf/NaN. However, the odds of it NOT supporting those (since Perl should be using IEEE 754 floats for NV) are practically zero.

Hopefully, I've covered all possible types of floats found in the wild. If not, let me know and I'll add it in. (For that matter, let me know if I'm missing any type found in the wild.)


This module started out as MooX::Types::CLike. Since Type::Tiny came about, that module has been translated to work with TT's API. Both Types::Numbers and this module are the result.


The project homepage is

The latest version of this module is available from the Comprehensive Perl Archive Network (CPAN). Visit to find a CPAN site near you, or see


Internet Relay Chat

You can get live help by using IRC ( Internet Relay Chat ). If you don't know what IRC is, please read this excellent guide: Please be courteous and patient when talking to us, as we might be busy or sleeping! You can join those networks/channels and get help:


    You can connect to the server at '' and talk to this person for help: SineSwiper.

Bugs / Feature Requests

Please report any bugs or feature requests via


Brendan Byrd <>


This software is Copyright (c) 2013 by Brendan Byrd.

This is free software, licensed under:

  The Artistic License 2.0 (GPL Compatible)