in reply to Re: Overloading '=' doesn't DWIM
in thread Overloading '=' doesn't DWIM

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

Replies are listed 'Best First'.
Re^3: Overloading '=' doesn't DWIM
by BrowserUk (Patriarch) on May 02, 2007 at 00:27 UTC

    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";