# Rational number objects in Perl using closures # This time, we'll use a Perl hash able instead of another function # as the "interface" to our objects. sub makerat { my ($n,$d) = @_; ($d!=0) || die "denominator can't be zero"; # define methods my ($gcd,$eq,$mult,$tostring); # Euclid's algorithm - this should be considered private $gcd = sub { my ($a,$b) = @_; if ($a==0) {$b} else {$gcd->($b%$a,$a)} }; my $g = $gcd->($n,$d); # reduce fraction $n = $n/$g; $d = $d/$g; # rational equality $eq = sub { my $B = $_[0]; ($n * $B->{denominator} == $d*$B->{numerator}); }; $tostring = sub { $n."/".$d }; $mult = sub { my $B = $_[0]; makerat($n*$B->{numerator}, $d*$B->{denominator}) }; # return interface as a hash table { numerator => $n, denominator => $d, tostring => $tostring, eq => $eq, mult => $mult } } # makerat # Note that by inserting the numerator and denominator into a hash table, # They effectively become "public" - anyone can access and modify them as # they do any other hash table entry. To make them read-only, you # will still need to write "accessor" functions to encapsulate them as # variables inside function closures. $a = makerat(2,6); $b = makerat(1,3); print $a->{numerator}, "\n"; print $a->{tostring}->(), "\n"; if ($a->{eq}->($b)) {print "equal\n"} else {print "not equal\n"} $c = $a->{mult}->($b); print $c->{tostring}->(), "\n";