I'm implementing an i18n framework for my webapp, and trying to make it as transparent as possible: you don't need to know that a variable contains a string that will be magically translated into your chosen language. It just works, eg:

my @days = _('Mon'),_('Tues'),_('Wed'),_('Thurs'),_('Fri'),_('S +at'),_('Sun'); sub day_of_week { my $self = shift; return $days[ $self->{day_num} ]; }

The idea is that any string marked with _( ) gets translated automatically. But there are two "phases": compilation and runtime. At runtime, I map *::_ to a sub which does the translation, but at compile time, I map *::_ to a sub which blesses the string into a simple overloaded class, that looks like this:

package i18n::String; use strict; use warnings; no warnings 'once'; use overload q{""} => sub { $i18n::Current_Lang->maketext( ${ $_[0] } ) }; sub new { my $class = shift; my $string = shift; return bless( \$string, $class ); } 1;

This class delays the translation of the string until the moment that the string needs to be used / stringified, at which point the overloaded stringification calls maketext on the original string.

The problem:

For the most part, this is transparent. I don't need to care whether variables contain strings-to-be-translated or just ordinary strings. The one place where this falls down is ref.

I know that we SHOULD care about the actual return value of ref, but how often do we just leave that out of our code:

sub good { my %params = ref $_[0] eq 'HASH? ? %{shift @_} : @_; } sub bad_but_typical { my %params = ref $_[0] ? %{shift @_} : @_; }

The only thing I could come up with to make this work is this:

{ no strict 'refs'; my $zero_isa = '0::ISA'; # Use a symbolic reference to + make package '0' *$zero_isa = ['i18n::String']; # inherit from i18n::String } package i18n::String; use strict; use warnings; no warnings 'once'; use overload q{""} => sub { $i18n::Current_Lang->maketext( ${ $_[0] } ) }; sub new { my $class = shift; my $string = shift; return bless( \$string,'0' ); # bless the scalar ref into +class '0' instead of $class } 1;

That works, because calling ref $string_object returns zero, which is false. But it's one of those things you hope never to see in production code. And of course, once you've used the "0" class for one object type, you can't use it for any others (unless you were to store the original class name as a property of the object, and let class '0' redispatch it to the correct class.)


So is the answer to this just "teach your fellow developers to program more defensively", or is there another way around it?


In reply to How do I pretend a reference isn't a reference by clinton

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.