@{$self->{templates}}{ keys %{$tmpls} } =
map ref $_ eq 'SCALAR' ? \"${$_}" : \"$_", values %{$tmpls} ;
discuss amongst yourselves. topics include: what does it do? wtf am i
doing that? and general esthetics.
that is from my soon to be birthed module Template::Simple. yes, another
template module. but this does have some interesting differences and it
really is simple and yet powerful. i gave a talk at boston.pm and 2
lightning talks at yapc::na and oscon and there was some interest in
it. if you want a work in progress snapshot, i will post the url here.
uri
--
Uri Guttman ------ u...@stemsystems.com -------- http://www.stemsystems.com
--Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org
Uri> @{$self->{templates}}{ keys %{$tmpls} } =
Uri> map ref $_ eq 'SCALAR' ? \"${$_}" : \"$_", values %{$tmpls} ;
Uri> discuss amongst yourselves. topics include: what does it do?
Uh, it throws a lot of warnings when values(%$tmpls) has non-references?
What do I win?
--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<mer...@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!
Why would it throw warnings? ref() returns empty string if the argument
isn't a reference.
Ronald
>this line of my code grew to its present form which i find amusing.
>
> @{$self->{templates}}{ keys %{$tmpls} } =
> map ref $_ eq 'SCALAR' ? \"${$_}" : \"$_", values %{$tmpls} ;
>
>discuss amongst yourselves. topics include: what does it do? wtf am i
>doing that? and general esthetics.
It makes a ref to a (stringified) copy of every scalar, or dereferenced
scalar ref.
Why would anyone take a copy instead of using an alias? Well, duh! To
make it safe to modify without touching the original, of course. Why you
are storing references instead of the string values, I don't know. It
won't save space.
BTW I assume this module is the subject of the slides at
<http://www.sysarch.com/tiny_template/slides/index.html>, no?
--
Bart.
>>>>> "Uri" == Uri Guttman <u...@stemsystems.com> writes:
Uri> @{$self->{templates}}{ keys %{$tmpls} } =
Uri> map ref $_ eq 'SCALAR' ? \"${$_}" : \"$_", values %{$tmpls} ;
Uri> discuss amongst yourselves. topics include: what does it do?
RLS> Uh, it throws a lot of warnings when values(%$tmpls) has
RLS> non-references?
it will only throw an uninitialized warning if a value is undef. that is
a user data error and not my problem. :) if the data is another ref
type, it will just stringify that ref and again it is user data
error. maybe i will add some checking code in version .02 for those two
cases.
RLS> What do I win?
not much as you sent in an incorrect comment!
BL> On Thu, 07 Sep 2006 03:29:02 -0400, Uri Guttman wrote:
>> this line of my code grew to its present form which i find amusing.
>>
>> @{$self->{templates}}{ keys %{$tmpls} } =
>> map ref $_ eq 'SCALAR' ? \"${$_}" : \"$_", values %{$tmpls} ;
>>
>> discuss amongst yourselves. topics include: what does it do? wtf am i
>> doing that? and general esthetics.
BL> It makes a ref to a (stringified) copy of every scalar, or dereferenced
BL> scalar ref.
1 point for that!
BL> Why would anyone take a copy instead of using an alias? Well, duh! To
BL> make it safe to modify without touching the original, of course. Why you
BL> are storing references instead of the string values, I don't know. It
BL> won't save space.
it saves copying around between methods and such. loading a template
from a file is done with file::slurp returning a scalar ref. and the
template cache lookup is done via another method which also wants to
return a ref. i could store the cached templates as plain scalars but i
went this way (for at least today! :). internally scalar refs are passed
around and only copies are made when they will be modified. and since
the templates can be passed in as scalar refs, i wanted to make sure the
cached templates are not modifiable from the outside, hence the copying
in that line of code.
BL> BTW I assume this module is the subject of the slides at
BL> <http://www.sysarch.com/tiny_template/slides/index.html>, no?
yep. that also has the original 42 line hack version of this module.
Ronald> Why would it throw warnings? ref() returns empty string if the argument
Ronald> isn't a reference.
At one point, I'm sure it returned undef on a non-reference.
Maybe I'm getting too old.
> >>>>> "Ronald" == Ronald J Kimball <rjk-pe...@tamias.net> writes:
>
> Ronald> Why would it throw warnings? ref() returns empty string if
> Ronald> the argument isn't a reference.
>
> At one point, I'm sure it returned undef on a non-reference.
reftype in Scalar::Util returns undef on a non-reference, so maybe
that's what you were thinking of.
Smylers
I concur with Randal. I early on got in the habit of
extra testing to avoid this warning. I'm glad I don't
have to anymore...
--
John Douglas Porter
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
> @{$self->{templates}}{ keys %{$tmpls} } =
> map ref $_ eq 'SCALAR' ? \"${$_}" : \"$_", values %{$tmpls} ;
>
> discuss amongst yourselves. topics include: what does it do? wtf am i
> doing that? and general esthetics.
I think you meant to post this to thedailywtf.com and not here.
(Although this list could be considered a crazier, more frightening
version of thedailywtf.com, I guess...)
my ( $k, $v );
$self->templates->{ $k } = ref $v eq 'SCALAR' ? \"${$v}" : \"$v"
while ( $k, $v ) = each %$tmpls;
Hmm. Don’t think I like that better.
[ delete 3 different attempts to make it better ]
Ugh. I think the core problem is that Perl actually does very
little to help you operate on hashes as a whole.
Regards,
--
Aristotle Pagaltzis // <http://plasmasturm.org/>
If we're looking for ways to do it differently, possibly better:
my %copy = %$tmpls;
$_ = ref $_ ? \"$$_" : \"$_" for values %copy;
@{$self->{templates}}{ keys %copy } = values %copy;
Three statements vs 1, and a temporary variable...
I'm not sure that's better either. Maybe clearer.
That was one of the deleted attempts. Hmm, let me refactor…
my %copy = %$tmpls;
$_ = \( ref $_ eq 'SCALAR' ? "$$_" : "$_" ) for values %copy;
@{$self->{templates}}{ keys %copy } = values %copy;
Hmm, rewriting it that way makes it more amenable to pulling out.
sub flatten_copy {
local $_ = shift;
ref $_ eq 'SCALAR' ? "$$_" : "$_";
}
my %copy = %$tmpls;
$_ = \( flatten_copy $_ ) for values %copy;
@{$self->{templates}}{ keys %copy } = values %copy;
I like that. My previous attempts at encapsulating that
expression felt dirty, because I didn’t notice that taking the
reference could be factored out. This separation of concerns, in
contrast, feels right.
Hmm, `values %copy` is there twice… Not really necessary with the
cleaned up copy expression, I think. But nesting derefs deeply is
always hard to read in Perl, so…
sub flatten_copy {
local $_ = shift;
ref $_ eq 'SCALAR' ? "$$_" : "$_";
}
my $t = $self->{templates};
@{$t}{ keys %$tmpls } = map \( flatten_copy $_ ), values %$tmpls;
I think I like that.
[ ... ]
> sub flatten_copy {
> local $_ = shift;
> ref $_ eq 'SCALAR' ? "$$_" : "$_";
> }
>
> my $t = $self->{templates};
> @{$t}{ keys %$tmpls } = map \( flatten_copy $_ ), values %$tmpls;
>
> I think I like that.
Why did you use "local"? Shouldn't the following work?
sub flatten_copy {
my $s = shift;
ref $s eq 'SCALAR' ? "$$s" : "$s";
}
Chris
--
Chris Dolan, Software Developer, Clotho Advanced Media Inc.
608-294-7900, fax 294-7025, 1435 E Main St, Madison WI 53703
vCard: http://www.chrisdolan.net/ChrisDolan.vcf
Clotho Advanced Media, Inc. - Creators of MediaLandscape Software
(http://www.media-landscape.com/) and partners in the revolutionary
Croquet project (http://www.opencroquet.org/)
Excellent!
I believe it's better to do
ref $_ ? "$$_" : "$_"
than
ref $_ eq 'SCALAR' ? "$$_" : "$_"
because, in the first case, you get an actual error
in the exceptional case (a ref of the wrong type),
whereas in the latter case you get a useless and
wrong string in the value, which you might not catch
until later, if ever.
If you really want to test the ref type, do so
robustly using the methods in Scalar::Util.
Works the same. I often use `local $_` in tiny functions that
mangle just a single value. Matter of taste/style.
Excellent points, both of them; I’ll make a mental note.
> * Chris Dolan <ch...@clotho.com> [2006-09-08 17:10]:
>> Why did you use "local"? Shouldn't the following work?
>>
>> sub flatten_copy {
>> my $s = shift;
>> ref $s eq 'SCALAR' ? "$$s" : "$s";
>> }
>
> Works the same. I often use `local $_` in tiny functions that
> mangle just a single value. Matter of taste/style.
Ahh, I see -- cargo cult. ;-)
Changing the topic a little bit... I've always suspected there was a
speed difference between local and my. So, I just benchmarked the
two versions, and "my" wins by a wide margin:
% perl test.pl
Rate local my
local 467290/s -- -33%
my 699301/s 50% --
% perl -v
This is perl, v5.8.6 built for darwin-thread-multi-2level
(with 2 registered patches, see perl -V for more detail)
============= test.pl ==============
#!/usr/bin/perl -w
use strict;
use Benchmark qw(cmpthese);
my $s = 'foo';
$_ = 'foo';
cmpthese(1_000_000, {
'local' => sub {
flatten_copy_local('bar');
},
'my' => sub {
flatten_copy_my('bar');
},
});
sub flatten_copy_local {
local $_ = shift;
ref $_ eq 'SCALAR' ? "$$_" : "$_";
}
sub flatten_copy_my {
my $s = shift;
ref $s eq 'SCALAR' ? "$$s" : "$s";
}
========================================
CD> Ahh, I see -- cargo cult. ;-)
CD> Changing the topic a little bit... I've always suspected there was a
CD> speed difference between local and my. So, I just benchmarked the
CD> two versions, and "my" wins by a wide margin:
CD> % perl test.pl
CD> Rate local my
CD> local 467290/s -- -33%
CD> my 699301/s 50% --
makes perfect sense. my vars are not in the symbol table and just need
an initialization at run time and they exist in the pad of a sub. localized
vars need to save the previous value in some form of a stack (real work)
and also get initialized. so local should be slower. as for the cargo
cult, i agree. use local only when you MUST use it. mjd has a good
article on the 7 valid uses of local. just declaring vars in a sub is
not one of them.
Err, what? I chose that style for myself. I didn’t pick it up
from anyone else and certainly not unthinkingly.
> I just benchmarked the two versions, and "my" wins by a wide
> margin:
>
> % perl test.pl
> Rate local my
> local 467290/s -- -33%
> my 699301/s 50% --
I dunno if that was supposed to be an argument, but I couldn’t
care less. I hope I don’t have to explain why as well.
* Uri Guttman <u...@stemsystems.com> [2006-09-09 05:40]:
> use local only when you MUST use it. mjd has a good article on
> the 7 valid uses of local. just declaring vars in a sub is not
> one of them.
If you use $_ in any way within a sub, you better localise it or
someone who calls your code is going to be very surprised at some
point (that includes yourself).
And using no variable is again quite a bit faster (A thing I found very
disappointing for the sake of readable code).
| ice:~/some_random_test>./perl_local_my_speed_test.pl
| Rate local my global novar
| local 549356/s -- -16% -22% -39%
| my 656410/s 19% -- -7% -27%
| global 703297/s 28% 7% -- -21%
| novar 895105/s 63% 36% 27% --
| ice:~/some_random_test>perl -v
|
| This is perl, v5.8.8 built for i386-freebsd-64int
| (with 1 registered patch, see perl -V for more detail)
Here is the modified script.
#!/usr/bin/perl -w
use strict;
use Benchmark qw(cmpthese);
cmpthese(1_000_000, {
'local' => sub {
flatten_copy_local('bar');
},
'my' => sub {
flatten_copy_my('bar');
},
'global' => sub {
flatten_copy_global('bar');
},
'novar' => sub {
flatten_copy_novar('bar');
},
});
sub flatten_copy_local {
local $_ = shift;
ref $_ eq 'SCALAR' ? "$$_" : "$_";
}
sub flatten_copy_my {
my $s = shift;
ref $s eq 'SCALAR' ? "$$s" : "$s";
}
sub flatten_copy_novar {
ref $_[0] eq 'SCALAR' ? "${$_[0]}" : "$_[0]";
}
no strict 'vars';
sub flatten_copy_global {
$s = shift;
ref $s eq 'SCALAR' ? "$$s" : "$s";
}
==============
CU,
Sec
--
The Feynman problem solving Algorithm
1) Write down the problem
2) Think real hard
3) Write down the answer
> * Chris Dolan <ch...@clotho.com> [2006-09-09 03:55]:
>>> Works the same. I often use `local $_` in tiny functions that
>>> mangle just a single value. Matter of taste/style.
>>
>> Ahh, I see -- cargo cult. ;-)
>
> Err, what? I chose that style for myself. I didn’t pick it up
> from anyone else and certainly not unthinkingly.
I didn't mean that to be insulting -- I was just teasing. In fact I
usually respect your contributions a lot, so I was curious why your
style was different from mine and if there was a reason why yours
might be better.
>> I just benchmarked the two versions, and "my" wins by a wide
>> margin:
>>
>> % perl test.pl
>> Rate local my
>> local 467290/s -- -33%
>> my 699301/s 50% --
>
> I dunno if that was supposed to be an argument, but I couldn’t
> care less. I hope I don’t have to explain why as well.
That was for my curiosity and to convince me, not to convince you.
That's why I changed the subject line in the message. I apologize
for my less-than-clear motives.
Chris
Why is why you can write « my $_ » in recent Perls, I think.
--
Philippe "BooK" Bruhat
Honesty is its own reward. Dishonesty is its own punishment.
(Moral from Groo The Wanderer #30 (Epic))
Nice. I’ll use that when it finds its way into a stable release.
:-)
* Chris Dolan <ch...@clotho.com> [2006-09-09 21:00]:
> I didn't mean that to be insulting -- I was just teasing. […]
> That was for my curiosity and to convince me, […] I apologize
> for my less-than-clear motives.
no problem, not your fault. I’m a bit impatient sometimes, which
can lead to unwarranted grumpiness.
>If you really want to test the ref type, do so
>robustly using the methods in Scalar::Util.
I'm not convinced that is indeed the best approach. So Uri expects
either a plain string, or a scalar ref to a string.
What if instead you get an object? Do you want to treat it as a scalar
ref, or as a plain string? IMO you *don't* want to peer inside the
intestines of an object, instead, you ought to treat the object as a
black box, *not* look at what kind of blessed ref it is, and thus, you
should be wanting to use the stringified object.
Thus: treat only an unblessed scalar ref as a scalar ref.
--
Bart.
I meant in general. I don't feel (as I said before) that
excessive ref testing is appropriate in situations like this.
But if you want to be anal, and throw your own exceptions
on the wrong types of refs, then Scalar::Util lets you
avoid having to reinvent the ref-testing wheel, mostly.
> But if you want to be anal, and throw your own exceptions on the wrong
> types of refs, then Scalar::Util lets you avoid having to reinvent the
> ref-testing wheel, mostly.
But please don't! I've encountered a few Cpan modules which want a
filename as a string. A Path::Class::File object overloads very nicely
as a string of a filename, but excessive reference testing by the
modules in question meant it got rejected.
Sorry, this isn't fun.
Smylers