in reply to Overloading '=' doesn't DWIM

You can't overload '=' actually. They give you a half-way solution, but it's deemed un-perl-ish to allow the overload of '='. It would "go against the camel-hair" to actually overload the assignment operator.

I have found that, not only is it un-intuitive, but it just plain never works how I expect. I think your LHS would have to be an object also, but it could be something else going wrong. The simplest solution is to just call your copy function directly instead of trying to overload '='. Even if you get it to work, it's going to cause trouble again some day.

I overload most of the other operators from time to time, but I never bother trying to get the shallow-copy to work.

-Paul

Replies are listed 'Best First'.
Re^2: Overloading '=' doesn't DWIM
by syphilis (Archbishop) on May 01, 2007 at 23:46 UTC
    They give you a half-way solution

    I wonder why do they do that ? If I can use overload '=' => \© then that ought to do something useful. (Ok ... so perhaps, in the right hands, it does do something useful.) And why is it considered un-perlish to overload '=' ? (Well ... I probably wouldn't understand the answer to that question, anyway.)

    call your copy function directly instead of trying to overload '='

    Yes - that's pretty much what the demo I posted does. Except that it contains an unnecessary function. The 'set_from_existing' function can be removed from the Inline::C section, the perl code in the script changed to:
    $num1 = Grief::new(113); $num2 = $num1; # Assign using _copy() $num3 = _copy($num1, '', ''); # Assign using _copy() _set_val($num1, 555); print _get_val($num2),"\n", _get_val($num3), "\n";
    and the rest of the post remains essentially unchanged. It still baffles me that $num3 gets created as a separate object, but $num2 gets created (by exactly the same function) as some sort of semi-object that (to begin with) is tied in some way to $num1, and never gets DESTROYed (even if the tie is subsequently broken).

    Thanks Paul. I can see no reason to disagree with your advice.

    Cheers,
    Rob

      I'm not sure if it is relevant--you may be aware already--but I added a couple of printfs to your code:

      SV * _copy( SV * arg_obj, SV * second, SV * third ) { Number * num_obj; SV * obj_ref, * obj; printf( "_copy:%p %p %p\n", arg_obj, second, third ); ... SV * _set_from_existing( SV * arg_obj ) { Number * num_obj; SV * obj_ref, * obj; printf( "_set::%p\n", arg_obj ); ...

      And it appears that the overloading is not causing your _copy() function to be called:

      Finished Build Compile Stage _set::0185E260 555 113 Destroying ...... destroyed Destroying ...... destroyed

      Which (as best I can tell) explains the output completely:

      $$num1 = Grief::new( 113 ); $num2 = $num1; # Assign using _copy( ) $num3 = _set_from_existing( $num1 ); # Assign using _set_from_existing +( ) _set_val( $num1, 555 ); print _get_val( $num2 ),"\n", _get_val( $num3 ), "\n"; __END__

      $num2, in the absence of the overloading is simply an alias to $num1, whereas $num3 is explicitely as new object with the same value. When you set $num1 to 555, you are also setting $num2, as they are both references to the same object.

      All of which is probably not news to you. The only real question as far as I can see is if overload can't or won't allow you to overload assignment, why doesn't use overload '=' => \&_copy; throw an error?


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        And it appears that the overloading is not causing your _copy() function to be called

        Damn!! ... that's the oversight I was ... ummmm ... overlooking. I should've thought to stick a printf() in there as a check. Thanks for picking that up.

        Another approach is to simply comment out the 'use overload ...' code - which has no effect on the output of the script at all. Oh, well .... live and learn ....

        why doesn't use overload '=' => \&_copy; throw an error?

        Good question. Thanks BrowserUK.

        Cheers,
        Rob
        Update: I think, at last, I start to see the light. The overloading of the assignment operator takes its effect only when the value of either $num1 or $num2 is subsequently altered using an overloaded operator. Consider the following:
        use warnings; use Devel::Peek; package Grief; use overload '++' => \&_inc, '=' => \&_copy, ; use Inline C => Config => BUILD_NOISY => 1; use Inline C => <<'EOC'; typedef struct { long num; } Number; SV * new(SV * x) { Number * num_obj; SV * obj_ref, * obj; New(1, num_obj, 1, Number); if(num_obj == NULL) croak("Failed to allocate memory in new() function"); obj_ref = newSViv(0); obj = newSVrv(obj_ref, "Grief"); num_obj->num = SvUV(x); sv_setiv(obj, (IV)num_obj); SvREADONLY_on(obj); return obj_ref; } SV * _get_val(SV * obj) { return newSVuv(((Number*)SvIV(SvRV(obj)))->num); } void _inc(SV * obj, SV * second, SV * third) { (((Number*)SvIV(SvRV(obj)))->num)++; } SV * _copy(SV * arg_obj, SV * second, SV * third) { Number * num_obj; SV * obj_ref, * obj; printf( "_copy:%p %p %p\n", arg_obj, second, third ); New(1, num_obj, 1, Number); if(num_obj == NULL) croak("Failed to allocate memory in _copy() function"); obj_ref = newSViv(0); obj = newSVrv(obj_ref, "Grief"); num_obj->num = ((Number*)SvIV(SvRV(arg_obj)))->num; sv_setiv(obj, (IV)num_obj); SvREADONLY_on(obj); return obj_ref; } void DESTROY(SV * obj) { printf("Destroying ..."); Number * number = (Number*)SvIV(SvRV(obj)); Safefree(number); printf("... destroyed\n"); } EOC $num1 = Grief::new(113); $num2 = $num1; $num3 = _copy($num1, '', ''); #Run any one of the following 4 lines $num1++; # _copy() gets called, 3 objects DESTROYed #$num2++; # _copy() gets called, 3 objects DESTROYed #_inc($num1, '', ''); # no _copy(), 2 objects DESTROYed #_inc($num2, '', ''); # no _copy(), 2 objects DESTROYed print _get_val($num2)," | ", _get_val($num3), "\n";