G.6. What Is an Object Value?

When you call a constructor like Net::FTP->new(hostname), you get back an object value, which is a value you can later use, in combination with a method name, to call object methods.

Now, so far we've been pretending, in the above examples, that the variables $session or $loan are the objects you're dealing with. This idea is innocuous up to a point, but it's really a misconception that will, at best, limit you in what you know how to do. The reality is not that the variables $session or $query are objects; it's a little more indirect—they hold values that symbolize objects. The kind of value that $session or $query hold is what I'm calling an object value.

To understand what kind of value this is, first think about the other kinds of scalar values you know about: The first two types of scalar values you probably ever ran into in Perl are numbers and strings, which you learned (or just assumed) will usually turn into each other on demand; that is, the three-character string "2.5" can become the quantity two and a half, and vice versa. Then, especially if you started using perl -w early on, you learned about the undefined value, which can turn into 0 if you treat it as a number, or the empty-string if you treat it as a string.[9]

[9] You may also have been learning about references, in which case you're ready to hear that object values are just a kind of reference, except that they reflect the class that created thing they point to, instead of merely being a plain old array reference, hash reference, etc. If this makes sense to you, and you want to know more about how objects are implemented in Perl, have a look at the perltoot manpage.

And now you're learning about object values. An object value is a value that points to a data structure somewhere in memory, which is where all the attributes for this object are stored. That data structure as a whole belongs to a class (probably the one you named in the constructor method, like ClassName->new), so that the object value can be used as part of object method calls.

If you want to actually see what an object value is, you might try just saying print $object. That'll get you something like this:

Net::FTP=GLOB(0x20154240)

or:

Business::US_Amort=HASH(0x15424020)

That's not very helpful if you wanted to really get at the object's insides, but that's because the object value is only a symbol for the object. This may all sound very abstruse and metaphysical, so a real-world allegory might be very helpful.

You get an advertisement in the mail saying that you have been (im)personally selected to have the rare privilege of applying for a credit card. For whatever reason, this offer sounds good to you, so you fill out the form and mail it back to the credit card company. They gleefully approve the application and create your account, and send you a card with a number on it.

Now, you can do things with the number on that card—clerks at stores can ring up things you want to buy, and charge your account by keying in the number on the card. You can pay for things you order online by punching in the card number as part of your online order. You can pay off part of the account by sending the credit card people some of your money (well, a check) with some note (usually the pre-printed slip) that has the card number for the account you want to pay toward. And you should be able to call the credit card company's computer and ask it things about the card, like its balance, its credit limit, its APR, and maybe an itemization of recent purchases and payments.

Now, what you're really doing is manipulating a credit card account, a completely abstract entity with some data attached to it (balance, APR, etc.). But for ease of access, you have a credit card number that is a symbol for that account. Now, that symbol is just a bunch of digits, and the number is effectively meaningless and useless in and of itself—but in the appropriate context, it's understood to mean the credit card account you're accessing.

This is exactly the relationship between objects and object values, and from this analogy, several facts about object values are a bit more explicable:

Internally, an object value has a basically different type from a string, or a number, or the undefined value—if $x holds a real string, then that value's slot in memory says "this is a value of type string, and its characters are...," whereas if it's an object value, the value's slot in memory says, "this is a value of type reference, and the location in memory that it points to is..." (and by looking at what's at that location, Perl can tell the class of what's there).

Perl programmers typically don't have to think about all these details of Perl's internals. Many other languages force you to be more conscious of the differences between all of these (and also between types of numbers, which are stored differently depending on their size and whether they have fractional parts). But Perl does its best to hide the different types of scalars from you—it turns numbers into strings and back as needed, and takes the string or number representation of undef or of object values as needed. However, you can't go from a string representation of an object value, back to an object value. And that's why this doesn't work:

$x = Net::FTP->new('ftp.aol.com');
$y = Net::FTP->new('ftp.netcom.com');
$z = Net::FTP->new('ftp.qualcomm.com');
$all = join(' ', $x,$y,$z);           # !!!
...later...
($aol, $netcom, $qualcomm) = split(' ', $all);  # !!!
$aol->login("sburke", "aoeuaoeu");
$netcom->login("sburke", "qjkxqjkx");
$qualcomm->login("smb", "dhtndhtn");

This fails because $aol ends up holding merely the string representation of the object value from $x, not the object value itself—when join tried to join the characters of the "strings" $x, $y, and $z, Perl saw that they weren't strings at all, so it gave join their string representations.

Unfortunately, this distinction between object values and their string representations doesn't really fit into the analogy of credit card numbers, because credit card numbers really are numbers—even thought they don't express any meaningful quantity, if you stored them in a database as a quantity (as opposed to just an ASCII string), that wouldn't stop them from being valid as credit card numbers.

This may seem rather academic, but there's two common mistakes programmers new to objects often make, which make sense only in terms of the distinction between object values and their string representations.

The first common error involves forgetting (or never having known in the first place) that when you go to use a value as a hash key, Perl uses the string representation of that value. When you want to use the numeric value two and a half as a key, Perl turns it into the three-character string "2.5." But if you then want to use that string as a number, Perl will treat it as meaning two and a half, so you're usually none the wiser that Perl converted the number to a string and back. But recall that Perl can't turn strings back into objects—so if you tried to use a Net::FTP object value as a hash key, Perl actually used its string representation, like Net::FTP=GLOB(0x20154240), but that string is unusable as an object value. (Incidentally, there's a module Tie::RefHash that implements hashes that do let you use real object-values as keys.)

The second common error with object values is in trying to save an object value to disk (whether printing it to a file, or storing it in a conventional database file). All you'll get is the string, which will be useless.

When you want to save an object and restore it later, you may find that the object's class already provides a method specifically for this. For example, MIDI::Opus provides methods for writing an object to disk as a standard MIDI file. The file can later be read back into memory by a MIDI::Opus constructor method, which will return a new MIDI::Opus object representing whatever file you tell it to read into memory. Similar methods are available with, for example, classes that manipulate graphic images and can save them to files, which can be read back later.

But some classes, like Business::US_Amort, provide no such methods for storing an object in a file. When this is the case, you can try using any of the Data::Dumper, Storable, or FreezeThaw modules. Using these is unproblematic for objects of most classes, but may run into limitations with others. For example, a Business::US_Amort object can be turned into a string with Data::Dumper, and that string written to a file. When it's restored later, its attributes will be accessible as normal. But in the unlikely case that the loan object was saved in mid-calculation, the calculation may not be resumable. This is because of the way that that particular class does its calculations, but similar limitations may occur with objects from other classes.

But often, even wanting to save an object is basically wrong—what would saving an ftp session even mean? Saving the hostname, username, and password? current directory on both machines? the local TCP/IP port number? In the case of "saving" a Net::FTP object, you're better off just saving whatever details you actually need for your own purposes, so that you can make a new object later and just set those values for it.