Re: Git.pm

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 10 May 2012 18:18, Subho Banerjee <subs.zero@xxxxxxxxx> wrote:
> Hello Yves,
> I am aware of that. But you see the problem is that using eval/warn/do
> is that the $@ has to be localized every time eval is called.

It doesn't *have* to be localized every time. Although it does help a
bit. On the other hand it also hinders.

> From my
> understanding of how the Try::Tiny package works, this is exactly what
> happens. So we are just calling a simple eval statement but in a block
> where the $@ is handled properly, which is eventually what we would
> have to do if we wrote it ourselves(Though I am not sure about how DBI
> does it, I will have a look into that). And that is why I arrived in
> favor of the Try::Tiny module in the first place. Well, that and the
> ability to throw exception objects if required.

As far as I know Try::Tiny exists because of a bug in Perl.

The bug is that since $@ is a global, if an object is created in an
eval, and then its DESTROY itself does an eval it can "hide" the
error, if one uses eval incorrectly. However if one does things
correctly one can detect this case regardless, although perhaps in the
process losing the error message. Ny simply arranging that every eval
statements returns a true value then you can ALWAYS detect when an
eval failed, even if $@ is clobbered.

$ perl -le'sub Foo::DESTROY { print "in DESTROY"; eval 1 } my $ok=
eval q(my $o= bless {}, "Foo"; my $zero=0; print 1/$zero; 1); if ($@)
{ print $@ } if (!$ok) { print "error in eval: ", $@||"Zombie Error"}'
in DESTROY
error in eval: Zombie Error

remove the eval 1 in the DESTROY method:

$ perl -le'sub Foo::DESTROY { print "in DESTROY"; } my $ok= eval q(my
$o= bless {}, "Foo"; my $zero=0; print 1/$zero; 1); if ($@) { print $@
} if (!$ok) { print "error in eval: ", $@||"Zombie Error"}'
in DESTROY
Illegal division by zero at (eval 1) line 1.

error in eval: Illegal division by zero at (eval 1) line 1.

Now it is true that using local does somewhat save things, however
ONLY if EVERYONE uses local when they eval. Which they dont. Nor do
they use Try::Tiny. So in regards to localization the only thing
Try::Tiny saves you from is other people using Try::Tiny or similar
functionality.

Now, it is true that Try::Tiny arranges to check the eval, and it
localizes $@, so I suppose it does save some people from shooting
themselves in the foot. But Perl is most definitely not about not
shooting yourself in the foot, indeed, if you ask it nicely Perl will
hand you a loaded shotgun to make it easier.

Basically all Try::Tiny does is make:

try {
     do_something();
} catch {
     do_something_with_error($_);
};

behave the same as this:

local $@;
eval {
    do_something();
    1;
} or do {
    my $error= $@ || "Zombie Error";
    do_something_with_error($error);
};

Which for me is silly. Id rather see the code than have a module wrap
it up in sub calls, replace $@ with $_ and related junk. Yes this
requires Perl programmers to know their stuff. But then so does any
non-trivial programming task.

Now notice some issues with Try::Tiny, it doesnt support string eval
anyway, so you can just swap it into the code I wrote, nor the general
case of eval. And even if you use it, it doesnt save you if the code
you are executing does not ALSO use it:

$ perl -MTry::Tiny -le'sub Foo::DESTROY { print "in DESTROY"; eval 1 }
my $ok= eval {my $o= bless {}, "Foo"; my $zero=0; print 1/$zero; 1};
if ($@) { print $@ } if (!$ok) { print "error in eval: ", $@||"Zombie
Error"}'
in DESTROY
error in eval: Zombie Error
$ perl -MTry::Tiny -le'sub Foo::DESTROY { print "in DESTROY"; eval 1 }
my $ok= try {my $o= bless {}, "Foo"; my $zero=0; print 1/$zero; 1}; if
($@) { print $@ } if (!$ok) { print "error in eval: ", $@||"Zombie
Error"}'
in DESTROY
error in eval: Zombie Error
$ perl -MTry::Tiny -le'sub Foo::DESTROY { print "in DESTROY"; eval 1 }
my $ok= try {my $o= bless {}, "Foo"; my $zero=0; print 1/$zero; 1}
catch { print "error in eval: ", $_||"Zombie Error"}'
in DESTROY
error in eval: Zombie Error

Notice how it provides no more benefit than writing eval like this:

eval {
     stuff();
     1; # this is important
} or do {
     my $error= $@ || "zombie error"; # must do this as early as possible
     do_something_with_error($error);
};

And for me, if I see code written like this I KNOW it works, i know
what side effects it has (localizing $@ has its own issues), and I
know I can understand it.

So for me Try::Tiny is a waste of time. Using it saves you from almost
nothing, and just forces consumers of your code to know how to do eval
properly AND how Try::Tiny works. Not using Try::Tiny at all means
people JUST have to know how to use eval properly, which if they want
to do any kind of real Perl work they need to know anyway.

Anyway, on the side of annoying you about Perl trivia, you can find a
lot of reusable library code in git-deploy on github. Feel free to
steal whatever you like.

  https://github.com/git-deploy

I would have loved to have a better git library module than Git.pm
when I wrote the original version of git-deploy. So I am all in favour
of your project.

cheers,
Yves








-- 
perl -Mre=debug -e "/just|another|perl|hacker/"
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]