Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery

Re^3: Reference assessment techniques and how they fail

by dragonchild (Archbishop)
on Feb 17, 2008 at 20:32 UTC ( #668448=note: print w/replies, xml ) Need Help??

in reply to Re^2: Reference assessment techniques and how they fail
in thread Reference assessment techniques and how they fail

%{} is set, but shouldn't respond because nothing has been set.
my $scalar = 'abcd'; my $obj = Object::MultiType->new( scalar => $scalar );
The whole tying thing is, for example, DBM::Deep. dbm-deep provides both TIEARRAY and TIEHASH and all appropriate methods in subclasses. Those methods didn't have to be in subclasses. It might be useful to test.

Also, reftype(), when implemented in pureperl (such as when installed without a compiler), reblesses to a string that shouldn't be a class, but might. That should be tested.

Frankly, I would be more interested in figuring out how to make sub isHash { eval { %{ $_[0] }; 1 }; } work without warnings. That seems to be a saner solution because it has perl figuring out how Perl works.

My criteria for good software:
  1. Does it work?
  2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?

Replies are listed 'Best First'.
Re^4: Reference assessment techniques and how they fail
by kyle (Abbot) on Feb 18, 2008 at 02:12 UTC

    I'll start by saying I don't really understand your remarks about DBM::Deep and tie.

    use Object::MultiType; my $scalar = 'abcd'; my $obj = Object::MultiType->new( scalar => $scalar ); print %{$obj} ? 'hash' : 'empty hash', "\n"; __END__ empty hash

    Object::MultiType does not die here, so eval would see it the same as everything else. (I had a much longer test set for this, but it doesn't really add anything to what I put in Re^4: Reference assessment techniques and how they fail. Specifically, eval has the side effect of calling overload methods, but blokhead's test doesn't.)

    We seem to be talking about a difference between the interface as presented and the interface as implemented. That is, maybe it says it can be a hash, but then it croaks when you try to treat it as one. I think there's a whole range of non-function between total failure and total invulnerability. One side of that range (total failure) is where eval outperforms less invasive checks. The other advantage it seems to have is future-proofing against someday there being another kind of scalar that that acts as a hash but doesn't match the less invasive checks. Are those two advantages bigger than determining type without possibly calling unknown code?

    (In case it's not obvious, the subtext of my original article is that determining type—reliably—should be easier than this.)

    Looking at the code for Scalar::Util::reftype, I don't see where it reblesses. Its vulnerability seems to be that it relies on the object not to have a particular instance method (a_sub_not_likely_to_be_here), which it has defined in UNIVERSAL. Elsewhere refaddr blesses into 'Scalar::Util::Fake', apparently to keep from calling an overloaded stringifier.

      Just a quick note that I tested some form of eval-style test and was pleasantly surprised to find that no overloaded tied methods were actually invoked by the test (as I recall). So my preference is an eval-style test that doesn't run any user code. When such is indeed possible, then it wins (or ties) at both criteria. Unfortunately, I don't have the exact check code nor test handy and I won't be likely to dive into the details of that in the immediate future, it appears. But coming up with eval-style tests that won't emit warnings and demonstrating that they don't call user code (or how little user code they call) would be useful results (hopefully from this thread).

      When such isn't possible, then I wouldn't want to use your preferred test unless it came rolled up in a core module such as overload (or, next best, Scalar::Util) so that the next time this stuff changes (or a problem is found) the test is likely to get updated. Of course, that still leaves the problem of using it in a backward-compatible way. For the optimists in the crowd, that reduces to just requiring the install of an updated overload module. But getting something a ton better than what Scalar::Util has managed to provide is long overdue and would certainly be welcomed by me. :)

      Updated: to note that I was testing tied items, not overloaded.

      - tye        

        When I tested eval, it did invoke overload methods. Here's the test (see also Re^4: Reference assessment techniques and how they fail for a longer version for code refs):

        use strict; use warnings; use Test::More 'tests' => 4; use Scalar::Util qw( blessed reftype ); my $side_effect = 0; package OverloadHash; use overload '%{}' => sub { $side_effect = 1; {} }; package main; sub is_hash_eval { no warnings qw( void uninitialized ); return '' ne ref $_[0] && eval { %{$_[0]}; 1 }; } sub is_hash_util { my $suspected_hash = shift; return 0 if '' eq ref $suspected_hash; return 1 if 'HASH' eq reftype $suspected_hash; if ( blessed $suspected_hash && overload::Method( $suspected_hash, '%{}' ) ) { return 1; } return 0; } check_method( \&is_hash_util, 'utils' ); check_method( \&is_hash_eval, 'eval' ); sub check_method { my ( $tester, $name ) = @_; $side_effect = 0; my $overhash = bless {}, 'OverloadHash'; ok( $tester->( $overhash ), "$name: overloaded reference" ); # this test fails for the eval method ok( ! $side_effect, "$name: no side effect" ); }

        I agree that the best solution to all this would be something sweet in Scalar::Util. I trust it to stay up to date, and it's the right place for it.

        Here's a test for side effects of an eval test on a tied array.

        It seems the reason nothing is called during the test is that it's happening in void context. If I give the array dereference a context in the eval, it has to make a call to the object.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://668448]
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (8)
As of 2017-05-28 11:26 GMT
Find Nodes?
    Voting Booth?