Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Bless a string

by Sewi (Friar)
on Dec 01, 2011 at 09:33 UTC ( [id://941021]=perlquestion: print w/replies, xml ) Need Help??

Sewi has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

I know that the following usage of Perl is not suggested and may cause trouble because things are not like they look. It's a very special usage case and I won't ever use this for new designs.

We're using a selfmade template module to load, modify and output templates:

my $template = Project::Template::load($filename); $template = Project::Template::replace($template, \%substitution_value +s);

I'ld like to allow template functions to be used on the template variable itself like

$template->replace(\%substitution_values);

for fewer typing and less error risks.

I know how to handle this on the sub/method side, but I can't replace $template (currently containing HTML source) by bless {}, __PACKAGE__ as some source parts still modify $template's contents in place.

MongoDB::OID is using a blessed scalar for it's self-generated IDs. It's a plain scalar when being print'ed but is blessed on MongoDB::OID when Dumper()ed or ref()ed.

MongoDB is using C for building these ID objects and I clearly don't like them because it took me hours until I noticed that they were blessed. My usage case is only being used by a small team of developers and it would be clearly documentated.

Is it possible to bless a scalar value using pure Perl? bless $string, __PACKAGE__; doesn't work (Can't bless a non-reference).

Thanks,
Sewi

Replies are listed 'Best First'.
Re: Bless a string
by moritz (Cardinal) on Dec 01, 2011 at 09:48 UTC

    As the error message explains, you can only pass references to bless, so do that:

    bless \$string;

    (The second argument of bless defaults to __PACKAGE__, so no reason to repeat that).

    Note that the blessing sticks to the string, not to the reference, so you can access the package information even if you only pass the string itself around:

    $ perl -wE 'my $s = "foo"; bless \$s; say ref \$s' main
        bless should always use the two-argument-form, see Perl::Critic::Policy::ClassHierarchies::ProhibitOneArgBless

        Just because there's a Perl::Critic policy for something doesn't mean you should always do it that way.

        The better approach is to know what you're doing, and then make an informed decision on how you do it.

        The reason that many people recommend two-argument bless() is that your constructors work with subclassing, when you write things like sub new { my $class = shift; bless {}, $class; }.

        But when you don't use a variable as the second value, but instead a value that is known at compile time, and still hold on to the believe that code gets magially better if you use the 2-argument form of bless, you're in the realm of cargo cult programming.

        And that's not at all what "Perl Best Practices" is about -- making you think about your code is the real reason behind the book.

        Usage of a reference is no option because too many existing files are manipulating the scalar itself.

        Not sure what you're saying. As moritz explicitly pointed out, it's the string (or more precisely, the SV) that's getting the blessing, not the reference. It's just that bless needs a reference as argument.

        Maybe this will convince you that the blessing is associated with the SV itself:

        $ perl -MDevel::Peek -we 'my $s = "foo"; bless \$s, "bar"; Dump $s' SV = PVMG(0x7acff0) at 0x790610 REFCNT = 1 FLAGS = (PADMY,OBJECT,POK,pPOK) IV = 0 NV = 0 PV = 0x7826d0 "foo"\0 CUR = 3 LEN = 8 STASH = 0x7877c0 "bar"
Re: Bless a string
by roboticus (Chancellor) on Dec 01, 2011 at 11:42 UTC

    Sewi:

    That's nifty:

    $ cat string_obj.pl #!/usr/bin/perl use strict; use warnings; my %vars = qw(bar shizzle baz diddle foo voodoo ); print "vars: ", join(", ", map { "!$_=>'$vars{$_}'" } sort keys %vars), "\n\n"; my $template = '!foo bar !baz'; my $object = bless \$template, 'TemplateStr'; print "template='$template'\n"; my $str = $object->doit(%vars); print "str='$str'\n\n"; $template = 'foo !bar baz'; print "template='$template'\n"; $str = $object->doit(%vars); print "str='$str'\n\n"; package TemplateStr; sub doit { my ($self, %v) = @_; my $rv = $$self; for my $k (keys %v) { $rv =~ s/!$k/$v{$k}/g; } return $rv; } $ ./string_obj.pl vars: !bar=>'shizzle', !baz=>'diddle', !foo=>'voodoo' template='!foo bar !baz' str='voodoo bar diddle' template='foo !bar baz' str='foo shizzle baz'

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

Re: Bless a string
by pemungkah (Priest) on Dec 02, 2011 at 00:48 UTC
    Well, overload might be useful to redefine the operations that are being done on the string to check if the operand is a member of your class, dereference it, do the operation, and put it back. Do something similar to the CORE:: functions that will be used on these faked strings.

    Definitely not something I'd deploy in production, as I'd never be sure if I got all the operations and functions that were going to be used...

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://941021]
Approved by moritz
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (3)
As of 2024-04-24 21:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found