ISO-8859-1 is a simple 8-bit character encoding, which represents the
first 256 Unicode characters (codepoints 0x00 to 0xff) in one octet each.
This is how strings were historically represented in Perl. A string
represented this way is referred to as downgraded.
UTF-8 is a variable-width character encoding, which represents all
possible Unicode codepoints in differing numbers of octets. A design
feature of UTF-8 is that ASCII characters (codepoints 0x00 to 0x7f)
are each represented in a single octet, identically to their ISO-8859-1
encoding. Perl has its own variant of UTF-8, which can handle a wider
range of codepoints than Unicode formally allows. A string represented
in this variant UTF-8 is referred to as upgraded.
A Perl string is physically represented as a string of octets along with
a flag that says whether the string is downgraded or upgraded. At this
level, to determine the Unicode codepoints that are represented requires
examining both parts of the representation. If the string contains only
ASCII characters then the octet sequence is identical in either encoding,
but Perl still maintains an encoding flag on such a string. A string
is always either downgraded or upgraded; it is never both or neither.
When handling string input, it is good form to operate only on the Unicode
characters represented by the string, ignoring the manner in which they
are encoded. Basic string operations such as concatenation work this way
(except for a bug in perl 5.6.0), so simple code written in pure Perl is
generally safe on this front. Pieces of character-based code can pass
around strings among themselves, and always get consistent behaviour,
without worrying about the way in which the characters are encoded.
However, due to an historical accident, a lot of C code that interfaces
with Perl looks at the octets used to represent a string without also
examining the encoding flag. Such code gives inconsistent behaviour for
the same character sequence represented in the different ways. In perl
5.6, many pure Perl operations (such as regular expression matching)
also work this way, though some of them can be induced to work correctly
by using the utf8 pragma. In perl 5.8, regular expression matching
is character-based by default, but many I/O functions (such as open)
are still octet-based.
Where code that operates on the octets of a string must be used by code
that operates on characters, the latter needs to pay attention to the
encoding of its strings. Commonly, the octet-based code expects its
input to be represented in a particular encoding, in which case the
character-based code must oblige by forcing strings to that encoding
before they are passed in. There are other usage patterns too.
You will be least confused if you think about a Perl string as a character
sequence plus an encoding flag. You should normally operate on the
character sequence and not care about the encoding flag. Occasionally you
must pay attention to the flag in addition to the characters. Unless you
are writing C code, you should try not to think about a string the other
way round, as an octet sequence plus encoding flag.