http://qs1969.pair.com?node_id=385489

I'm working on a module named Data::Alias to provide a comprehensive set of aliasing operations. For those who don't know, aliasing is getting two expressions to identify exactly the same thing. So while setting $x to $y will make $x and $y the same, aliasing $x to $y will make \$x and \$y the same (Diagram).

Its interface is simple: alias LIST or alias BLOCK. The function itself is essentially a no-op, but the entire argument list is evaluated with altered semantics where aliasing occurs wheever copying would normally be done. This is achieved by diddling the optree, not by using a source filter.

This means you can use natural perl syntax to do all sorts of aliasing:

alias my ($x, $y) = @_;Named aliases for sub arguments
alias @x = @{$self->{Items}};Alias for some referenced array
$x = alias [$y, $z];An anonymous array of aliases
(just like $x = sub{\@_}->($y, $z))
alias push @x, $y;Push an alias onto an array

Currently it supports aliasing assignment to variables, array/hash elements, dereferencing, and globs, including conditional assignment (&&=, ||=). Also push, unshift, splice, and anonymous array/hash constructors. do-blocks return aliases (in fact, they are lvalues). Finally you can return aliases from sub or eval, either implicitly by placing the sub/eval inside alias, or explicitly by using alias return LIST;

UPDATE: Putting a conditional expr ( ? :) on the left-side of assignment didn't work. I've added support for it and uploaded a new snapshot.

So the big question is... have I overlooked anything? Are there more operations that deserve to receive aliasing semantics inside alias?

A minor second issue what to do with aliasing elements of tied arrays and hashes. Currently I just give an error, but I considered checking for special methods like ALIAS_STORE, ALIAS_PUSH, etc. Would this be of any utility at all?

And any other sort of feedback is welcome too of course :-)

Replies are listed 'Best First'.
Re: RFC: Is there more to alias? (cases)
by tye (Sage) on Aug 24, 2004 at 22:37 UTC

    Say I have an object, $heap. And say I want to store some really whopping huge strings in this heap. But $heap was not written to know about aliases and I don't want to add the overhead of putting references into the heap and telling it to use a dereferencing comparison function.

    Is there much chance that I could use:

    alias $heap->Push( $dna );

    to acheive a heap of aliases? My understanding of your description says "no". Would it make sense to be able to copy an opcode tree and transform the copy like:

    my $heapPush= aliasize $heap->can("Push"); $heapPush->( $heap, $dna );

    (noting that routines called by $heapPush would still remain unaffected, perhaps unfortunately)

    How would you go about retrofitting a module to support storing aliases instead of copies?

    On a related note, compare these two bits of code:

    my @x; sub swap { my( $i, $j )= @_; alias @x[$i,$j]= @x[$j,$i]; } sub exchange { my( $i, $j )= @_; alias do { my $t= $x[$i]; $x[$i]= $x[$j]; $x[$j]= $t; }; }

    Do these cases work?

    swap( 0, 1 ); exchange( 0, 1 ); swap( 0, 0 );

    I expect I could work that out for myself but I don't want to expend the effort and I thought you might appreciate the opportunity. (:

    BTW, smashing great idea for a module.

    - tye        

      Ehh, hmmm, alias-ifying someone else's code? I can already smell the sulphurous fumes of the dragons that await you down that road. Most likely you'd manage to break something by doing that, and even if it miraculously works, it could very well break when the module is updated. I've just examined some Heap module to imagine what would happen.. at the very least all subs that operate on the heap (directly or indirectly) would need to be aliasified to have any chance of working correctly. I really wouldn't go down this road.

      So, this also answers simply how to retrofit a module to store aliases: always use aliasing internally, and make a copy at the API boundary when aliasing is not desired.

      Your swap and exchange are both fine and functionally equivalent, the cases you suggest work. Note that you can omit the 'do' in exchange, since alias BLOCK is valid syntax.

Re: RFC: Is there more to alias?
by tilly (Archbishop) on Aug 25, 2004 at 02:18 UTC
    I know that you didn't use a source filter to implement this, but someone will want a source filter variant so that the Perl 6 syntax of := can be supported. So you might think about ways to support that.

    In that line of thought, what happens when you do this?

    my @y = 1..10; alias my @x = @y; push @y, 11; print map "$_\n", @x;
    Will @x turn out to have 1..11 or 1..10 at this point?

    The answer should be clearly documented, and will matter a lot if someone wants to make the source filter that I suggested above.

      1..11. If the lhs of assignment is a bare unparenthesized array or hash, the whole thing is aliased. If it's in parens (alias my (@x) = @y), then the contents will be aliased. This is actually in the documentation under "list assignment to whole aggregate".

      I'm not going to do source filtering myself, but the author of Perl6::Binding is of course free to use Data::Alias as "back-end".

      UPDATE: On a side note.. I've now already answered a few "would this work?"-questions.. why doesn't anyone just download and try? perl is an empirical science, remember! :-D

      Heh, I wonder if I'm missing something, but it appears that Data::Alias's interface is better in several ways than Perl6's. How will Perl6 support the following tasks other than with these relatively ugly hacks:

      $w = alias [$x, $y, $z]; # vs. $w[0] := $x; $w[1] := $y; $w[2] := $z; alias push @x, $y; # vs. push @x, 0; @x[-1] := $y; alias my( @x )= @y; # vs. @x= (); @x[$_] := @y[$_] for 0 .. @y.last; alias my( @x )= GetList(); # vs. is this possible with Perl6's syntax?

      Perhaps Perl6 should have 'alias' built in along with the more succinct := operator?

      - tye        

        The following might work, and if so would cover several of the cases:

        push @x, my $x := $_ for @y;

        But that's still much clumsier than Data::Alias.

        I have a hunch though that in Perl6 we'll be using the splat to do this, something remotely looking like

        *@x := *@y;

        Don't ask me about the precise syntax though.

        Makeshifts last the longest.

Re: RFC: Is there more to alias?
by fergal (Chaplain) on Aug 24, 2004 at 22:14 UTC
    Not a very helpful comment but could you explain about diddling the op tree and have you done it in a way that is easy to apply to other problems? It's something that could be very useful in other cirumstances (I'm thinking about real macros).

      The hard part was getting any sort of "trigger" on the occurrence of alias (which is just a declared but undefined sub). The breakthrough was the discovery of PL_check and the fact it's editable.

      This array contains a list of "check functions" which are invoked whenever a node is created in the op-tree. I used it to trigger on OP_RV2CV (the occurrence of "alias" or "copy") and OP_ENTERSUB (the completion of the op-subtree that invokes it). I do some initial modifications of the op-tree, and in particular mark is so I can find it later.

      When alias/copy has been seen I also temporarily override PL_peepp. There I scan the optree for markings and do the actual work, which consists mostly of setting the op_ppaddr of various ops inside alias to aliasing equivalents.

      A final piece of the puzzle is supporting alias BLOCK which involves a lexer hack, but is mostly unrelated to the rest.

      It may indeed be applicable in other situations. I was already thinking about how I could make this mechanism more reusable.

      Any further details you want?

        Interesting but scary! It looks like the same technique could be used to implement compile-time checking of method calls, so I could do something like
        type Dog my $a; $a->bark; $a->$trick; # compile time warning maybe $a->perform_brain_surgery; # compile time error
        a bit like Java interfaces except far less painful. So it would pick up typos in method names but doesn't try to look at the Class of $a (although an optional assertion might be useful).

        Rereading your original posting, I can't follow

        $x = alias [$y, $z]; alias push @x, $y;
        Doesn't something have to be aliased to something else? What is being aliased to what in these examples?
Re: RFC: Is there more to alias?
by ysth (Canon) on Aug 25, 2004 at 05:15 UTC
    Clarification, please: Would  @x = @y alias @x to @y, so push/shift/clear/whatever done to one would affect the other, while  @x[0..$#x] = @y[0..$#y] would alias only the array elements, not the whole array, so that push/shift/clear/whatever done to one array would leave the other unaffected?
      Yes.

      Note that alias @x[0..$#x] = @y[0..$#y] would only do what you probably want when $#x == $#y. If you simply want to replace the contents of @x with aliases, use alias +(@x) = @y (or perhaps alias((@x) = @y), matter of taste)

Re: RFC: Is there more to alias?
by Sidhekin (Priest) on Aug 24, 2004 at 22:28 UTC

    I'll make sure to check it out after some sleep. Meanwhile, file this under "any other sort of feedback":

    my $x = "123"; alias substr($x, 1, 1) = $x; print $x;

    (Does humming or whistling go better with this?)

    print "Just another Perl ${\(trickster and hacker)},"
    The Sidhekin proves Sidhe did it!

      Unsupported no-copy target at - line 2

      Were you expecting anything else from this? I mean, I don't see how it could do anything useful.

      (btw, the module was initially named Data::NoCopy.. I'll change the error message to "Unsupported alias target" and check for any other leftover "no-copies")

      UPDATE: I've updated and reuploaded the module with the fixed error message.

        Were you expecting anything else from this? I mean, I don't see how it could do anything useful.

        Nope, or at least, nothing useful (I'm just happy that it does not break any harder). It just seemed to my sleep-deprived mind a case of a feedback loop (if it was made to "work"), and as you explicitly welcomed "any other sort of feedback" ... well, sleep-deprivation does strange things to my mind. Sorry.

        print "Just another Perl ${\(trickster and hacker)},"
        The Sidhekin proves Sidhe did it!

Re: RFC: Is there more to alias?
by Solo (Deacon) on Aug 25, 2004 at 03:55 UTC
    POD seemed to imply this wasn't supported (by not saying it was), but I wanted to ask in case it was obvious... can implicit assignment to $_ be aliased? As in

    for alias my $line (<DATA>) {}

    I'd probably never want to alias $_, just a curiosity.

    I don't see anything about filehandles in the POD, either, as in

    alias my $line = <DATA>; while ( defined( alias my $line = <DATA> ) ) {}

    I'm not sure what I'd expect from the first, but the second involves another implicit assignment to $_. Would that work as 'expected'?

    Deref is especially cool and I look forward to that very much. ++

    --Solo

    --
    You said you wanted to be around when I made a mistake; well, this could be it, sweetheart.
      Attempting to follow xmath's advice and try myself. Unfortunately, I'm out of my league with xs compilation errors. (I can build Date::Calc, so it's not an environment problem.)

      Are there compiler options I'm missing?

        I think I've fixed the problem, and I've uploaded a fresh version. See if this helps.

        As for your original questions.. I have read your original post several times, and I have honestly no idea what you're trying to accomplish....

        for alias my $line (<DATA>) {}
        This is a syntax error. And "for" already aliases, so what's the deal here? On top of that, why would you need an alias to the temporary var that contains the line anyway?

        alias my $line = <DATA>; while ( defined( alias my $line = <DATA> ) ) {}
        These work, but again I don't see the point.. why alias $line to the read line? To prevent copying the line? I think perl already optimizes that away.

        Maybe I'm just missing something, in which case please enlighten me.