Preamble: In most C-inspired programming languages, comparisons such as 3 < 2 < 1 would produce a slightly unsettling true result. This is because it's evaluated as (3 < 2) < 1, and 3 < 2, being false, numifies to 0. Whilst thinking upon this, a possible solution came to me...

Consider the comparison $x OP $y (where OP is one of (<|>|<=|>=|==|!=)). If $x is undef, or the comparison is false, it should return undef. Otherwise, it should return a true value that is numerically equivalent to $y ($y or "0 but true", as necessary).

This returned value will then become the LHS of the next comparison. If it is undef, that will propogate, giving an overall false result. Otherwise, it will be the correct number, as seen on the immediate LHS of this new comparison in the source code.

I have hacked a module to this effect together in perl, through extensive use of use overload;.

Unfortunately, perl's syntax does not allow you to chain together comparisons, even if they _are_ overloaded, so I have used the bitshift operators in their place. In true domino style, this has resulted in my having to omit the "*-or-equal" operators, as <<= and >>= (1) are right-associative and (2) must have an lvalue (ie not a constant) on their RHS.

Regardless of all that, here's a first draft of that module (beware: dangerously uncommented code follows):

[ UPDATE: taking diotalevi's comments into account ]

package ChainComparable; use strict; use UNIVERSAL (); sub new { my $class = shift; # allow for returning either a list or a scalar return wantarray ? (map { my $i = $_; bless \$i, $class } @_) : (bless \shift, $class); } sub comparison { # whee, currying my $sub = shift; return sub { my ($a, $b, $swap) = @_; $a = $$a; # allow for comparisons between two instances of this class $b = $$b if UNIVERSAL::isa($b, __PACKAGE__); # put the args in the right order ($a, $b) = ($b, $a) if $swap; if (defined $a and $sub->($a, $b)) { if ($b != 0) { return __PACKAGE__->new($b) } else { return __PACKAGE__->new("0 but true") } } else { return __PACKAGE__->new(undef) } }; } use overload ( bool => sub { $$_[0] }, '""' => sub { $$_[0] }, "0+" => sub { $$_[0] }, "==" => comparison(sub { $_[0] == $_[1] }), "!=" => comparison(sub { $_[0] != $_[1] }), "<<" => comparison(sub { $_[0] < $_[1] }), ">>" => comparison(sub { $_[0] > $_[1] }), );

Thoughts?


In reply to numbers with chainable comparisons by Irrelevant

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.