Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Do you consider these different or the same?

by demerphq (Chancellor)
on Jul 01, 2005 at 10:27 UTC ( [id://471639]=perlmeditation: print w/replies, xml ) Need Help??

I'd appeciate the monasteries help in meditating on something. Given the following two arrays, do you consider them to be equivelent or not?

my $x={}; my $y={}; my $z={}; my $ar1=[$x,$x]; my $ar2=[$y,$z];

Or in other words should they be considered to be deep copies of each other or not.

Now, if you said that yes they are equivelent, do you think they should be after

$_->[0]{a}='foo' for $ar1,$ar2;

Does this change your opinion or does it justify it or does it not make a difference?

UPDATE: The question this is trying to answer is what should Test::More::is_deeply() do?

My position is it should report the two structures as being different. Some folks take the other position. Im trying to determine what the community thinks.

---
$world=~s/war/peace/g

Replies are listed 'Best First'.
Re: Do you consider these different or the same?
by tmoertel (Chaplain) on Jul 01, 2005 at 16:50 UTC
    You are asking the wrong questions. Instead, ask –
    1. What is the purpose of Test::More::is_deeply?
    2. What, then, should its semantics be?

    My answer to the first is that is_deeply's purpose is to make it easy to test complex observed values by comparing them with given expected values.

    My answer to the second, then, is that is_deeply should consider the observed and expected values to be equivalent if both have the same structure and subvalues, ignoring sharing. (Remember, I am talking semantics here, not implementation.)

    Why ignore sharing? Because it rarely matters in tests. By ignoring it we make the common case easier for testers, who frequently hand-roll expected values. This goes back to the purpose of is_deeply; convenience matters.

    As to your questions, then, here is how I answer. In the first case, $ar1 and $ar2 are equivalent. Both have the same structure and subvalues – [{},{}]. In the second case, they are not equivalent; [{a=>'foo'},{a=>'foo'}] differs from [{a=>'foo'},{}].

    Cheers,
    Tom

      Exactly.

      Also note that the name "is_deeply" comes from the is() function that only cares about eq. So "is_deeply" is meant to convey applying eq deeply between two structures. Something that does more than that needs a different name if it is part of Test::More.

      The "deeply" part means that $a vs. "$a" fail the test if $a is a reference because only leaves are compared.

      - tye        

Re: Do you consider these different or the same?
by hv (Prior) on Jul 01, 2005 at 11:08 UTC

    I do not see them as deep copies of each other. Whether I'd see them as being "equivalent" would depend on context - I guess I'd think of them as "equivalent up to aliasing", which would be "equivalent enough" for some purposes and not for others.

    After the operation, I'd no longer see them as equivalent at all.

    Hugo

      As i mention in my update the question is motivated by trying to determine what the community thinks Test::More::is_deeply() should do. There is some debate on the perl-qa list as to what the correct behaviour is.

      ---
      $world=~s/war/peace/g

Re: Do you consider these different or the same?
by fergal (Chaplain) on Jul 01, 2005 at 12:04 UTC

    I guess it depends on whether I'm going to change the data afterwards. It also depends on why I'm comparing them.

    Let's say I'm testing my date and time library. All objects are supposed to be immutable points in in time, numbers of hours, dates etc and

    In this case since everything's immutable I don't care about identities, only values. So when I'm testing I'll have a bunch of expected values and a bunch of result values. I might reuse the same date object multiple times in the expected values even though the result values have multiple different occurrences of the same date value. I don't want that to be a problem.

    I don't think there's a right anwer, it should be possible to compare in both ways.

    Finally in relation to is_deeply, it considers

    $a=[]; is_deeply($a, "$a");
    to be a pass. It also compares string-overloaded objects as strings and refuses to look inside and it completely ignores blessings. I think is_deeply should just keep doing exactly what it's doing. I and others know exactly what it's doing. Sometimes I use it, mostly I don't but changing its behaviour at this stage risks breaking tests and causing confusion.

      I might reuse the same date object multiple times in the expected values even though the result values have multiple different occurrences of the same date value. I don't want that to be a problem.

      Then you dont want a deep comparison, you want a shallow comparison. In fact you want the proposed 'looks_like()' method.

      Finally in relation to is_deeply, it considers

      $a=[]; is_deeply($a, "$a");
      to be a pass.

      Actually it doesn't. At least not in version 0.60

      I and others know exactly what it's doing. Sometimes I use it, mostly I don't but changing its behaviour at this stage risks breaking tests and

      My position is that we can eliminate the confusion by making is_deeply() do a proper deep structural comparison and provide a different routine (that would conveniently share its implementation with is_deeply).

      Long term I believe this would clear up a LOT of misunderstanding about references that I see even experienced Perl programmers making. Misunderstanding such as is_deeply() considering $ar1 and $ar2 to be the same, which is just totally wrong.

      my ($x,$y,$ar1); $x=\$y; $y=\$x; $ar1=[$x,$y]; my $ar2; $ar2->[0]=\$ar2->[1]; $ar2->[1]=\$ar2->[0]; is_deeply($ar1,$ar2); #this is wrong, wrong, wrong.

      If is_deeply()'s behaviour doesn't change then it should have very large warnings on it that it doesnt do what it claims to do (that is checking if the objects are deep copies of each other.)

      ---
      $world=~s/war/peace/g

        Then you dont want a deep comparison, you want a shallow comparison. In fact you want the proposed 'looks_like()' method.

        Not if my date looks like {day => 5, month => 11, year => 2005} because I need to look inside again. You might argue that the date shouldn't look like that but I just chose date as an example of where you have what is really a value which who's identity is irrelevant. The only reason it even has an identity is because Perl (and many other languages) do not allow you to represent structured values except by using what you might call "anonymous variables". Haskell, relational databases and probably lots of other pure functional languages on the other hand do not force this although they do allow it if you explicitly request it.

        Actually it doesn't. At least not in version 0.60

        It didn't do that in ver 0.39 (or thereabouts) either but that was reverted because it also fixed (I considered it fixed anyway) the overloaded reference behaviour. Version 0.60 might undo that but it also removes comparison of subrefs and seems to be completely broken for overloaded values, so I wouldn't be too sure that that will stay that way for very long.

        Assuming the docs are correct though is_deeply will still never look inside an overloaded object which to my mind is a far bigger sin against deepness than this problem, also not checking blessedness means that 2 deeply equal values will not necessarily react in the same way to method calls (in fact one of them may not even be an object).

        I've spent plenty of time arguing about the right thing for is_deeply to do but I stopped when I was convinced that is_deeply is not going anywhere new and that the author was not interested in trying to make it go anywhere new. It seems that its author has now changed his mind somewhat (with the sub refs thing) but I actually think he was right in the first place. It does what it does and it's been doing that for years now. Changing it's behaviour now makes no sense to me.

        My position is that we can eliminate the confusion by making is_deeply() do a proper deep structural comparison and provide a different routine (that would conveniently share its implementation with is_deeply).

        Then I guess we need:

        is_deeply() is_truly() is_madly()

        Hugo

Re: Do you consider these different or the same?
by spurperl (Priest) on Jul 01, 2005 at 11:32 UTC
    How "equivalent" do you mean ? To resolve such philosophical questions, Common Lisp has no less than 5 equality operators that address various "equality" questions.

    See here for example, perhaps you'll find something to inspire an answer ?

      The one that looks closes is 'equal' however, its not clear how it defines "isomorphic". Assuming it defines it the same way I would (a reference used twice is different from two references, even if the content of the references is 'equal').

      ---
      $world=~s/war/peace/g

        I think "isomorphic" in this context means that the two datums are interchangeable. Not necessarily residing in the same memory location, though. eq is used to find out if it's actually the same reference.

        Besides, some languages/libraries can imlement a copy-on-write strategy (for example, QString in the Qt C++ library) that defy simple definitions.

Re: Do you consider these different or the same?
by brian_d_foy (Abbot) on Jul 01, 2005 at 17:57 UTC

    The Test::More is_deeply() test acts like all of the other tests in Test::More by comparing values, not references. If two independent variables (meaning I change one and the other stays as it was) happen to have the same values, I expect is_deeply to pass.

    What I don't expect, and don't want to test with is_deeply, is that the same operations will produce the same results.

    I can see what you want to test, but I don't think is_deeply should be the thing to do that. It lives in its own community of tests in Test::More that all have the same idea and the same way of looking at things. If you changed how is_deeply works you have to change a lot more in Test::More.

    In fairness, there are notes in the is_deeply docs pointing at other modules. If those don't work for you, make another one that does and then send in a doc patch. (Along with that doc patch could be something to remove the word "equivalent" from the docs, since I think that's where the confusion starts).

    --
    brian d foy <brian@stonehenge.com>
Re: Do you consider these different or the same?
by hardburn (Abbot) on Jul 01, 2005 at 12:36 UTC

    When I use is_deeply() in tests, I'm usually taking one datastructure that was returned by the code being tested, and another that I built that represents what I expect the code to return. Under that usage, is_deeply() needs to see both the posted datastructures as equal.

    I suspect that the various opinions on this issue will reflect how people use is_deeply() in practice.

    "There is no shame in being self-taught, only in not trying to learn in the first place." -- Atrus, Myst: The Book of D'ni.

      Under that usage, is_deeply() needs to see both the posted datastructures as equal.

      I dont understand. You want is_deeply() to gloss over the fact that your hand constructed example is different from what it returns? Why is this good? And please before you use the example that Schwern did in a post, think about somethign like this:

      my %expect_hash=(a=>1,b=>2); my @expect=({%expect_hash},{%expect_hash}); #versus my @copies=(\%expect_hash,\%expect_hash);

      Is the extra char too much price to pay for is_deeply() doing what its name says it does? (this isn't intended as a snarky question, I really am curious.)

      ---
      $world=~s/war/peace/g

        (I don't see the Schwern post you mentioned in this thread. Is it someplace else?)

        All I see for is_deeply()'s documentation is:

        Similar to is(), except that if $this and $that are hash or array references, it does a deep comparison walking each data structure to see if they are equivalent. If the two structures are different, it will display the place where they start differing.

        Which, to me, just means it will make sure all the values in the nested data structure are the same. Wheather the actual references are the same is irrelevent in most of the code I've encountered. Of course, there are always exceptions, so a seperate sub that has a more exact definition of equivilence is likely needed.

        "There is no shame in being self-taught, only in not trying to learn in the first place." -- Atrus, Myst: The Book of D'ni.

Re: Do you consider these different or the same?
by tlm (Prior) on Jul 01, 2005 at 12:16 UTC

    This question is a bit philosophical... (Are you the same person you were 10 years ago? 10 months ago? 10 minutes ago?) I suppose that one could get at it via "majority rule", but I think the more fruitful approach is the one used by (for example) Scheme, which recognizes several levels of equality. (For Scheme these are, in increasing degree of stringency: equal?, eqv?, and eq?.) This approach recognizes the fact that different tasks demand different criteria for equality, instead of trying to shoehorn every situation into a single criterion for equality.

    the lowliest monk

      Actually in the bigger picture im arguing for exactly such a distinction. I beleive Test::More should supply a "looks_like()" function which wouldn't give a toss about reference counts and that the subroutine called is_deeply() should do what its name suggests and do a deep structural comparison (ie care about reference counts). Especially as I know that the code base currently handling is_deeply() can be relatively trivially be extended to support both behaviours.

      ---
      $world=~s/war/peace/g

Re: Do you consider these different or the same?
by itub (Priest) on Jul 01, 2005 at 13:54 UTC
    Sorry for editing this post so much, but I changed my mind a minute after posting and no one had replied to it yet:

    These are topologically different:

    my $ar1=[$x,$x]; my $ar2=[$y,$z];

    But these are the same:

    my $ar3=[$x,$x]; my $ar4=[$y,$y];

    That is, the comparison should care about the addresses of the references, but it should care about loops. Another way of looking at it is: deeply equivalent references should have the same canonical representation when dumped. Compare the following:

    # $ar1 $VAR1 = [ {}, $VAR1->[0] ]; # $ar2 $VAR1 = [ {}, {} ]; # $ar3 $VAR1 = [ {}, $VAR1->[0] ]; # $ar4 $VAR1 = [ {}, $VAR1->[0] ];
Re: Do you consider these different or the same?
by Arunbear (Prior) on Jul 01, 2005 at 11:38 UTC
    print "@$ar1\n@$ar2\n";
    produces:
    HASH(0x224fc8) HASH(0x224fc8) HASH(0x22507c) HASH(0x225088)
    so deep copies they are not.

      Although "deep copy" shows up in the original post, I think it's misplaced. The is_deeply docs don't say anything about testing whether or not they are deep copies. The other things in Test::More check for the same values, not the same references, and that's what I expect is_deeply to do, and for the "deeply" only to denote its descent into references to get their values.

      --
      brian d foy <brian@stonehenge.com>
Re: Do you consider these different or the same?
by Hena (Friar) on Jul 01, 2005 at 12:30 UTC
    I think I should read more on what is Test::More::is_deeply() is. But without reading that I would say no. They just look the same but doing
    $ar1->[0]{a}='foo'; $ar2->[0]{a}='bar';
    Then they are not the same anymore.

    After quick look at what is_deeply is, i don't know. It should explain what the subroutine is after. Eg. which is it

    1. Do these look the same to outside (at this particular moment)?
    2. Are these exatly identical in all ways?

    Depending what you want take your pick. But if both of these are wanted, then make two subroutines.
Re: Do you consider these different or the same?
by duelafn (Parson) on Jul 02, 2005 at 04:05 UTC

    I think that it is reasonable for a test module to consider them different since it is the safer approach (the whole point of testing in the first place). It is much easier (better) for someone to notice their test failing and replace is_deeply with is_deeply_not_so_strict (or whatever) than for someone to find out through a bug report that their test wasn't strict enough.

    Good Day,
        Dean

      I agree. It looks like tho in the end it wont change.

      ---
      $world=~s/war/peace/g

Re: Do you consider these different or the same?
by bageler (Hermit) on Jul 02, 2005 at 00:47 UTC
    I'd say six in one hand, half dozen in the other. Different but equivalent.
Re: Do you consider these different or the same?
by halley (Prior) on Jul 04, 2005 at 01:20 UTC
    When it comes to deep comparisons, I would define "equivalent" as being equal by value, and "identical" as sharing the identity.

    In my experience, it's RARELY useful to compare things as being identical beyond the top level scalar. It's COMMONLY useful to compare things as being equivalent to all depths.

    And lastly, if you like checking if things are identical, then you'll probably love seeing if things are equivalent to a certain depth, and identical below that depth. For example, { $x } is not identical to { $x }, because the curly braces produce two equivalent hashrefs with identical contents.

    --
    [ e d @ h a l l e y . c c ]

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://471639]
Approved by marto
Front-paged by grinder
help
Chatterbox?
and the web crawler heard nothing...

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

    No recent polls found