in reply to Is tie inteded to be used in this way?

That looks alright to me, the second version avoids repetition and is very clear, since that's done only once there's no need to worry about optimisation. You can do this with a for loop instead of the map (for two reasons: first, using map for turning a list into another and for for doing something with every element of a list makes the intent clearer, the second reason is that map in a void context will trigger the same kind of reactions as goto). I guess something with closures (I like closures :) ) could work, but I gave it a try and only ended up with something harder to read than your code. But here is another way to do it, in the spirit of TIMTOWTDI.

{ no strict 'refs'; *$_ = eval "sub { &main::trigger; shift()->SUPER::$_(\@_) }" for q +w(STORE CLEAR PUSH POP SHIFT UNSHIFT); }

Notice that I didn't use the "$self" scalar twice (well, I didn't use it at all actually), because $var->method(@params) already adds $var as the first parameter.

Your problem made me think of Python's decorators, so I ended up on this thread which could be of interest to you. The thing is, you may not want to modify the subs in Tie::StdArray, in case you use another module that uses this module, so you have to define your own methods anyway.

Edit : and I think you'll need to tie the contained scalars too if you want to call your trigger function only when your elements are modified. Your tied array should actually just tie any scalar pushed into it.

Replies are listed 'Best First'.
Re^2: Is tie inteded to be used in this way?
by choroba (Cardinal) on Apr 28, 2015 at 14:05 UTC
    No need for string eval:
    for (qw(STORE CLEAR PUSH POP SHIFT UNSHIFT)) { my $s = "SUPER::$_"; no strict 'refs'; *$_ = sub { &main::trigger; shift()->$s(@_) }; }

    Update: fixed error (removed the reference from \@_).

    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      Here's what I did when trying to use closures (I hadn't seen the issue with the double $self at the time):

      { no strict; for my $method (qw(STORE CLEAR PUSH POP SHIFT UNSHIFT)) { my $sub = "SUPER::$method"; *$method = sub { &main::trigger; my $self = shift; $self->$sub($se +lf, @_) }; } }
      So I felt that with all the lexicals and the use of many "advanced" features (anonymous sub, closing over a lexical, globs, scalar as a method, SUPER::) it was harder to read than a string eval which is often better understood. Your version is light enough that I like it more though.

      It's up to Discipulus to choose whatever he thinks he'll be able to understand the best :)

      very nice, thanks choroba
      anyway i like string eval for his extreme power: the compiler walk with you during the program execution. is just a matter of not abuse as i do sometimes.
      L*
      There are no rules, there are no thumbs..
      Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
        Hmm, eval is a beautiful function. I have used it to do slightly or even very geeky things. But in real production code, well, I have used it to check if I could open a file (when not being able to open it was not necessarily an error) or if a date was valid, when an invalid date was not sufficient to mandate an exception. (This happens, sometimes!). Not more.
        Je suis Charlie.
Re^2: Is tie inteded to be used in this way?
by Discipulus (Canon) on Apr 28, 2015 at 20:49 UTC
    Thanks Eily, for suggestions, links and (never understood) to explain me the inutility of $self explicitally set, as i've done.
    because $var->method(@params) already adds $var as the first parameter. was something i never realized.

    Anyway is not clear to me what do you means with and I think you'll need to tie the contained scalars too if you want to call your trigger function only when your elements are modified. Your tied array should actually just tie any scalar pushed into it.
    Are you refering in the case you change the value by reference (as i'll ask soon)? I have to tie the scalar values of each array elements?
    L*
    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

      I thought that while cases like $array[42] = "Doky" would work fine, $array[42] =~ tr/y/i/ or even s/D/L/ for @array; would not call STORE, but I just tried and have been proven wrong, at least for v5.14 :

      sub trigger{print "Triggered ".shift."(@_)\n"} #must go BEFORE the eva +l is seen {#bare block because package BLOCK appeared only 5.14 package Arraytrigger; use Tie::Array; use vars qw(@ISA); @ISA = ('Tie::StdArray'); for (qw(STORE CLEAR PUSH POP SHIFT UNSHIFT)) { my $s = "SUPER::$_"; no strict 'refs'; *$_ = sub { main::trigger($s, @_); shift()->$s(@_) }; } } tie my @arr, 'Arraytrigger'; @arr = qw(Doky); $arr[0] =~ tr/y/i/; s/D/L/ for @arr;