
# PODNAME: Types::Bool
# ABSTRACT: Booleans as objects for Perl

#pod =encoding utf8
#pod
#pod =head1 SYNOPSIS
#pod
#pod     use Types::Bool;
#pod
#pod     $true  = Types::Bool::true();
#pod     $false = Types::Bool::false();
#pod
#pod     is_bool( Types::Bool::true() );    # true
#pod     is_bool('xxx');                    # false
#pod
#pod     to_bool(1);     # Types::Bool::true()
#pod     to_bool('');    # Types::Bool::false()
#pod
#pod =head1 DESCRIPTION
#pod
#pod I<This is meant as a draft for a standard interface to boolean objects for Perl.>
#pod This is an alternative to I<bool.pm draft> in
#pod L<http://blogs.perl.org/users/tinita/2018/05/my-report-of-the-perl-toolchain-summit-2018-in-oslo.html>.
#pod
#pod Perl has no native representation for booleans.
#pod Most of the time the Perl concept of truth is enough.
#pod But when dealing with serialization of formats
#pod which support booleans, it is desirable to keep the
#pod booleans intact on round trips, eg. when writing after loading.
#pod And there are other good reasons for that,
#pod like strict validation via various mechanisms, like schemas,
#pod OpenAPI, type hierarchies, etc.
#pod
#pod A solution for that was adopted for JSON modules
#pod around 2012 by using references to C<1> or C<0>
#pod blessed into L<JSON::PP::Boolean> which was the
#pod chosen canonical package for these objects.
#pod
#pod The problem with that was the coupling with L<JSON::PP>
#pod for no apparent good reason. Booleans are independent
#pod of JSON and this association makes little sense
#pod when loading documents in formats like YAML, MessagePack, BSON, etc.
#pod However, the integration of the concept of boolean
#pod for all these applications is quite convenient.
#pod
#pod Marc Lehmann's L<Types::Serialiser> approached this problem
#pod by creating a common interface used by L<JSON::XS> and L<CBOR::XS>
#pod modules. This module lifts this core concept (including
#pod idea, implementation and documentation) into an isolated treatment
#pod for booleans only – so this can be proposed as the common
#pod ground for interoperability on booleans as objects for Perl modules.
#pod
#pod The implementation keeps the compatibility
#pod with the previous agreement on C<JSON::PP::Boolean>
#pod by making C<Types::Bool> stash an alias for C<JSON::PP::Boolean>.
#pod That means
#pod
#pod     Types::Bool::true->isa('JSON::PP::Boolean');
#pod
#pod but also
#pod
#pod     Types::Bool::true->isa('Types::Bool');
#pod
#pod This also allows an optimization to an isa test
#pod by direct comparison of stash pointers.
#pod
#pod =head2 INTERFACE
#pod
#pod L<Types::Bool> has two ready-to-use instances for true and false.
#pod
#pod     Types::Bool::true()
#pod
#pod     Types::Bool::false()
#pod
#pod L<Types::Bool> true values are represented as a reference
#pod to a scalar containing C<1> – implementations are allowed
#pod to directly test for this. For example, one can differentiate
#pod between a Perl true value and a L<Types::Bool> true by using this:
#pod
#pod     $value && Types::Bool::is_bool $value
#pod
#pod L<Types::Bool> false values are represented as a reference
#pod to a scalar containing C<0> - implementations are allowed
#pod to directly test for this.
#pod
#pod
#pod One can test if a value is a L<Types::Bool> with
#pod
#pod     Types::Bool::is_bool($value);
#pod
#pod Converting from a Perl true or false value into L<Types::Bool> can
#pod be done with
#pod
#pod     Types::Bool::to_bool($value);
#pod
#pod This minimum interface allows for easy and efficient implementation
#pod of other operations. Like negating booleans:
#pod
#pod     Types::Bool::to_bool( !$value );
#pod
#pod
#pod =head2 CORE CODE
#pod
#pod The code of this module would look as below, if not
#pod for the efforts to be compatible with L<JSON::PP>
#pod and L<Types::Serialiser> modules.
#pod
#pod     package Types::Bool;
#pod
#pod     use 5.005;
#pod     use Scalar::Util ();
#pod
#pod     use overload (
#pod         '0+' => sub { ${ $_[0] } },
#pod         '++' => sub { $_[0] = ${ $_[0] } + 1 },
#pod         '--' => sub { $_[0] = ${ $_[0] } - 1 },
#pod         fallback => 1,
#pod     );
#pod
#pod     use constant true  => bless \( my $dummy = 1 ), 'Types::Bool';
#pod     use constant false => bless \( my $dummy = 0 ), 'Types::Bool';
#pod
#pod     sub is_bool ($) { Scalar::Util::blessed( $_[0] ) and $_[0]->isa('Types::Bool') }
#pod
#pod     sub to_bool ($) { $_[0] ? true : false }
#pod
#pod =head1 FUNCTIONS
#pod
#pod L<Types::Bool> implements the following functions, which can be imported individually.
#pod
#pod =head2 false
#pod
#pod     $false = Types::Bool::false;
#pod
#pod Return the canonical "false" value.
#pod
#pod This function has a C<()> prototype and works as a constant
#pod (suitable for inlining by the Perl interpreter).
#pod
#pod =head2 is_bool
#pod
#pod     $is_bool = Types::Bool::is_bool($value);
#pod
#pod Return true if given a C<Types::Bool> object.
#pod Return false otherwise.
#pod
#pod This function has a C<($)> prototype.
#pod
#pod =head2 to_bool
#pod
#pod     $bool = Types::Bool::to_bool($value);
#pod
#pod Turns a true or false Perl value into
#pod C<Types::Bool::true> or C<Types::Bool::false>.
#pod
#pod This function has a C<($)> prototype.
#pod
#pod =head2 true
#pod
#pod     $true = Types::Bool::true;
#pod
#pod Return the canonical "true" value.
#pod
#pod This function has a C<()> prototype and works as a constant
#pod (suitable for inlining by the Perl interpreter).
#pod
#pod =head1 BUGS
#pod
#pod The use of L<overload> makes this module heavier.
#pod See L<Types::Serializer/"BUGS">.
#pod
#pod =head1 ACKNOWLEDGMENTS
#pod
#pod Original idea and code came from L<JSON::XS::Boolean> written by Marc Lehmann.
#pod
#pod =head1 SEE ALSO
#pod
#pod L<Types::Serialiser>
#pod
#pod L<JSON::XS>
#pod
#pod L<JSON::PP>
#pod
#pod L<Cpanel::JSON::XS>
#pod
#pod =cut

__END__

=pod

=encoding UTF-8

=head1 NAME

Types::Bool - Booleans as objects for Perl

=head1 VERSION

version 0.1.0

=head1 SYNOPSIS

    use Types::Bool;

    $true  = Types::Bool::true();
    $false = Types::Bool::false();

    is_bool( Types::Bool::true() );    # true
    is_bool('xxx');                    # false

    to_bool(1);     # Types::Bool::true()
    to_bool('');    # Types::Bool::false()

=head1 DESCRIPTION

I<This is meant as a draft for a standard interface to boolean objects for Perl.>
This is an alternative to I<bool.pm draft> in
L<http://blogs.perl.org/users/tinita/2018/05/my-report-of-the-perl-toolchain-summit-2018-in-oslo.html>.

Perl has no native representation for booleans.
Most of the time the Perl concept of truth is enough.
But when dealing with serialization of formats
which support booleans, it is desirable to keep the
booleans intact on round trips, eg. when writing after loading.
And there are other good reasons for that,
like strict validation via various mechanisms, like schemas,
OpenAPI, type hierarchies, etc.

A solution for that was adopted for JSON modules
around 2012 by using references to C<1> or C<0>
blessed into L<JSON::PP::Boolean> which was the
chosen canonical package for these objects.

The problem with that was the coupling with L<JSON::PP>
for no apparent good reason. Booleans are independent
of JSON and this association makes little sense
when loading documents in formats like YAML, MessagePack, BSON, etc.
However, the integration of the concept of boolean
for all these applications is quite convenient.

Marc Lehmann's L<Types::Serialiser> approached this problem
by creating a common interface used by L<JSON::XS> and L<CBOR::XS>
modules. This module lifts this core concept (including
idea, implementation and documentation) into an isolated treatment
for booleans only – so this can be proposed as the common
ground for interoperability on booleans as objects for Perl modules.

The implementation keeps the compatibility
with the previous agreement on C<JSON::PP::Boolean>
by making C<Types::Bool> stash an alias for C<JSON::PP::Boolean>.
That means

    Types::Bool::true->isa('JSON::PP::Boolean');

but also

    Types::Bool::true->isa('Types::Bool');

This also allows an optimization to an isa test
by direct comparison of stash pointers.

=head2 INTERFACE

L<Types::Bool> has two ready-to-use instances for true and false.

    Types::Bool::true()

    Types::Bool::false()

L<Types::Bool> true values are represented as a reference
to a scalar containing C<1> – implementations are allowed
to directly test for this. For example, one can differentiate
between a Perl true value and a L<Types::Bool> true by using this:

    $value && Types::Bool::is_bool $value

L<Types::Bool> false values are represented as a reference
to a scalar containing C<0> - implementations are allowed
to directly test for this.

One can test if a value is a L<Types::Bool> with

    Types::Bool::is_bool($value);

Converting from a Perl true or false value into L<Types::Bool> can
be done with

    Types::Bool::to_bool($value);

This minimum interface allows for easy and efficient implementation
of other operations. Like negating booleans:

    Types::Bool::to_bool( !$value );

=head2 CORE CODE

The code of this module would look as below, if not
for the efforts to be compatible with L<JSON::PP>
and L<Types::Serialiser> modules.

    package Types::Bool;

    use 5.005;
    use Scalar::Util ();

    use overload (
        '0+' => sub { ${ $_[0] } },
        '++' => sub { $_[0] = ${ $_[0] } + 1 },
        '--' => sub { $_[0] = ${ $_[0] } - 1 },
        fallback => 1,
    );

    use constant true  => bless \( my $dummy = 1 ), 'Types::Bool';
    use constant false => bless \( my $dummy = 0 ), 'Types::Bool';

    sub is_bool ($) { Scalar::Util::blessed( $_[0] ) and $_[0]->isa('Types::Bool') }

    sub to_bool ($) { $_[0] ? true : false }

=head1 FUNCTIONS

L<Types::Bool> implements the following functions, which can be imported individually.

=head2 false

    $false = Types::Bool::false;

Return the canonical "false" value.

This function has a C<()> prototype and works as a constant
(suitable for inlining by the Perl interpreter).

=head2 is_bool

    $is_bool = Types::Bool::is_bool($value);

Return true if given a C<Types::Bool> object.
Return false otherwise.

This function has a C<($)> prototype.

=head2 to_bool

    $bool = Types::Bool::to_bool($value);

Turns a true or false Perl value into
C<Types::Bool::true> or C<Types::Bool::false>.

This function has a C<($)> prototype.

=head2 true

    $true = Types::Bool::true;

Return the canonical "true" value.

This function has a C<()> prototype and works as a constant
(suitable for inlining by the Perl interpreter).

=head1 BUGS

The use of L<overload> makes this module heavier.
See L<Types::Serializer/"BUGS">.

=head1 ACKNOWLEDGMENTS

Original idea and code came from L<JSON::XS::Boolean> written by Marc Lehmann.

=head1 SEE ALSO

L<Types::Serialiser>

L<JSON::XS>

L<JSON::PP>

L<Cpanel::JSON::XS>

=head1 AUTHOR

Adriano Ferreira <ferreira@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2018 by Adriano Ferreira.

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

=cut
