Tie is probably one of the coolest features of modern Perl. The ability to encapsulate complex behaviors as if they were normal Perl datatypes is an enormously powerful idea. It is also enormously easy to abuse.

Here is my litmus test for when to use a tied interface:

Tie is used if you want to fool other code (perhaps not written by you) into doing complex things with what appears to be a normal Perl datatype without that code's knowledge.

Other code should not have to know that a given datatype is tied. If you need more than that, use a full-fledged object system (Perl has plenty of them: bless, Inside out Objects, etc.). Once you've written use Tie::Foo; tie my $data, 'Tie::Foo';, forget you ever wrote those lines until you need to call untie (and you may not need to).

A good use of the tied filehandle interface is GnuPG::Tie::Encrypt (and some of its brethern in the GnuPG namespace). You can pass the filehandle to any bit of code that writes to filehandles, and the data magically comes out the other end as encrypted text.

Tied hashes seem particularly easy to abuse, because it's easy to use them as full method calls. Tie::Google, Tie::Math, and Tie::Sysctl are good (bad) examples of this. They all perform operations that could work better as blessed objects (or whatever other object system you want). At best, they should be in the Acme:: namespace.

So if you're writting a module for tied use, stop to ask if you're better off with a real object.

----
I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
-- Schemer

: () { :|:& };:

Note: All code is untested, unless otherwise stated

Replies are listed 'Best First'.
Re: When to use Tie
by perrin (Chancellor) on Jan 29, 2004 at 16:13 UTC
    Don't forget, tie is also slow. It's actually faster to call the FETCH and STORE methods of a tied hash class directly than it is to use a tied hash.
      Well, that's obvious, isn't? It's even faster to execute the body of a FETCH or STORE directly, instead of calling the sub. Anything where you remove the red tape from is going to be faster. Whether it's a good idea remains to be seen.

      Abigail

        It's actually not obvious to many people, since tie is fairly magical. I have often been met with disbelief when I tell people this.
Re: When to use Tie
by tilly (Archbishop) on Jan 30, 2004 at 01:31 UTC
    My often stated opinion on tie is that it is a hack for a self-inflicted wound.

    The self-inflicted wound is that Perl makes an iron distinction between how you manipulate its native data types (scalars, arrays, hashes, filehandles, etc), and how you address user-created data types. From the syntax you can tell whether you have a native data type or a user-created data type. The hack is that Perl offers a wrapper to create something that looks like a native data type from a user-created data type. The hack has several drawbacks, however:

    1. It can add bugs. With different releases, the bugs move and overall seem to be getting better. But there remain places where tied objects don't quite do what they should. The reason for this is that tie is implemented by putting if checks in every operation that you might do with a Perl "thing". There are a lot of operations, and it is easy to miss something. Grabbing a random one, you couldn't untie a scalar within a tied FETCH until recently.
    2. It is not extensible. Well, it is if you are willing to tell people that they have to write tied(%foo)->bar("baz") to get at your extensions. But people tend to balk at that. So in practice tie only really works smoothly if the datatype that you are creating corresponds exactly to a native datatype.
    3. It is slow. I'm not just talking of the performance penalty for accessing a tied object. I'm also talking of the performance penalty for having every operation with native data types have to stop and check whether you are tied or not. If Perl lost tie, it would speed up most code by a reasonable margin.
    This is something that I clearly realized after I learned some Ruby. Unlike Perl, in Ruby everything is an object. Including native datatypes. Which means that the equivalent of tie doesn't even have to be written in Ruby, it is part of the language! (Well, actually the appropriate mix-ins needed to be written to make it easy to emulate native datatypes. But no core change was needed.) And the equivalent of a tied object lacks all of the drawbacks listed above.

    Of course the drawback for the way that Ruby does it is that you cannot syntactically tell what anything is. Therefore Ruby cannot auto-coerce as liberally as Perl, and cannot auto-vivify things.

    With all that said, what is my advice on tie? I'd say that people should use tie when Perl's syntactic design choices are getting in your way. If, however, you have reason to offer something that is a Perl datatype + more, then I'd bite the bullet and make it a real object.

      But tie isn't the only kind of magic there is, and all magic (except overload) is triggered by the same code checks. Most of the variables listed in perlvar use some form of magic (admittedly, a few do so uselessly; for example $^O).

      I thought untie within a FETCH used to work and got broken at some point along the way and then fixed. This is an area of valid complaint: magic really isn't well represented in perl's regression tests.

      Speaking of pervasive performance penalties, perl has an "optimization" of not reference counting items on the stack (including parameters in @_ in most cases). To keep things from getting garbage collected while still on the stack, it has tons of special code to mark things that should be kept even with a refcount of 0, and special code when dealing with arrays to check if the array at hand is @_ without refcounts. I've often wondered what the gain or loss would be if that mechanism were ripped out and regular reference counting were used for the stack, but its really to late now; there'd be too much work and too much danger of introducing bugs.

      My gripe with tie in the OP was more of a issue of theory. I specifically avoided implementation issues (like speed).

      To me, tie represents the ultimate in encapsulation. In theory, it is completely transparent after you've called tie (though as you mention, there are places where it's not transparent--these places should be considered bugs). It grates on me to see people treating tied hash lookups as if they were method calls, because you're willfully ignoring the reason for tie's existance. Speed is also a concern, but it would still annoy me even if it wasn't a factor.

      A short tangent on Ruby: I haven't learned a lot of this language, but what little I studied teached me a few things. I used to wonder why the Java people were in such a huff over integers not being objects. Why would you want to extend the behavior of an integer? Ruby showed me why: it's so you can call operations directly on the datatype, and thus (as you noted) eliminates the need for tie.

      ----
      I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
      -- Schemer

      : () { :|:& };:

      Note: All code is untested, unless otherwise stated

Re: When to use Tie
by shotgunefx (Parson) on Jan 29, 2004 at 16:19 UTC
    It's funny you bring this up. Looking through my older nodes, I came across something I wrote,Validate Country by ISO 3166 data. This is a tie class that lets you validate country codes. I was wondering for the life of me, why I wrote it as a tie. I think there was a reason at the time, but I was thinking as I looked at it,it was more suited for a function.

    On the other hand, I totally disagree about your comment that they belong under Acme:: namespace. If you don't want to use them, don't, but for someone else, this make perfect sense.


    -Lee

    "To be civilized is to deny one's nature."

      I don't view the Acme:: namespace as a "never use this in a real program" place. Rather, it's more of a "isn't this cute?" place. Making a tied hash that does Google searches (like Tie::Google) strikes me as something cute, but doesn't offer more functionality than Net::Google (which Tie::Google is based on).

      There are a few odd Acme:: modules that are both cute and useful in production code. I could imagine a few good uses of Acme::SoftwareUpdate. Acme::Morse::Audible might be useful in a Morse code trainer program.

      ----
      I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
      -- Schemer

      : () { :|:& };:

      Note: All code is untested, unless otherwise stated

        I agree with the assessment on Tie::Google, but my feeling is that if people want to do it, and people want to use it, that's fine with me. To someone else, this may be an intuitive way to address a problem.

        To me, Acme exists for interesting things of no practical value. I'd be hesitant to use Acme:: modules in anything production, solely on the name (Easy enough to cut and past into a new module though)

        -Lee

        "To be civilized is to deny one's nature."
Re: When to use Tie
by davido (Cardinal) on Jan 29, 2004 at 18:43 UTC
    If one of the goals of object orientation is to hide complexity, then tied datatypes are the ultimate objects. Though I agree that overuse of tie might confuse code maintainers, I believe it has a place in more instances than the narrow situation your post defines.

    Yes, tie can be used to produce ACMI:: type results, it can also be put to many legitimate uses. If all you need is a variable that acts in a special way, why bother with an unwieldy object interface? Tie is simply one more tool in the toolbelt of Perl programming. Use it where it's convenient and where it provides clarity or simplicity to design.


    Dave

Re: When to use Tie
by Anonymous Monk on Jan 29, 2004 at 23:46 UTC
    I consider object orientation to be even more abused; be it good or bad - it's all about the context and (implied) expectations.