このページは大阪弁化フィルタによって翻訳生成されたんですわ。

翻訳前ページへ


Chapter 1: Types, Values, and Variables
The Wayback Machine - http://web.archive.org/web/20130527104218/http://cog.cognitivity.com:80/perl6/val.html
Perl6 Object Oriented Cookbook (v0.2.1)  
  
 
Chapter 1: Types, Values, and Variables       Previous Page   Next Page

NOTE: this is a rough draft of some initial, "all-encompassing" documentation for Perl6, written so that newcomers to Perl6, and Perl in general, can easily understand it. Note that the first draft originally at this location has been temporarily moved to here, if you're looking for it. I don't recommend it, however.

Note that this is very detailed stuff, and so some of the details described herein are not necessarily accurate -- many have yet to be finalized! I will update each ASAP as individual decisions are made.

Questions, corrections, and general feedback are gratefully accepted -- please email me at mlazzaro@cognitivity.com.


At the core of any program is the manipulation of data. Whether the data is a mere set of bits, a document from a word processor, an image, the human genome, or anything else, the abstract goal is the same: to do something with that data.

In order to manipulate data, however, we must first define what it is that we're manipulating. Generally, programmers tend to talk about the type and the value of data.

  • A data type is the specific "kind of thing" that the data is. It could be a number, or a string, or a list of data elements, or anything else that the programming language recognizes. The type constrains the possible values of the data, by defining what values are "valid". Data types in Perl include num, str, Hash, Object, and a great many others.

  • A data value is, well, the actual value of the data. An element of data may be any value that the type of the data allows. For example, 5 and -7.2 are valid values for numeric data, and "Hello!" is a valid value for string data.

In general, the type and the value of the variable travel together. When programmers talk about the value of a variable, they most often mean the typed value -- the pairing of data type and data value that comprises, for the computer, what "thing" it's supposed to be working with.

(mjl -- need to explain defined-ness somewhere in here, too.)

Perl has a large number of builtin types, as well as the capability to add user-defined types. In general, however, all types belong to one of four broad "families":

  • A scalar represents a single unit of data. It could be a simple number or string, or a reference to a more complex object made up of many individual pieces.
  • An array is a list of elements of data. The list may contain one piece of data, or more than one, or none at all. (In Perl, lists can even be infinite.) All elements of the list may be of a single data type, or a list may contain elements from a variety of different types.
  • A hash is an indexed, unordered set of data (commonly known as an associative array.) A hash is made up keys and values: the keys represent named "buckets" for putting data in, and the values are the data in those buckets.
  • Code is a block of code that can be executed.

Scalar is by far the most encompassing of the four. A variable or value is a scalar if it is not an array, a hash, or code. As you'll see later, that's quite a broad definition.

Variables

If values are just things, variables are simply the names of containers for those things. You can put things in each container, and you can take things out of each container. Some of these containers are tailored to accept only certain types of values, while others are more liberal in what can be placed inside them. You can name each container anything you want, like "shoes" or "fish", in order to differentiate it from all the others you might have around.

In Perl, variable names always start with a special punctuation character, called a sigil. The sigil acts as a "signal" to Perl (and a reminder to you) that you will always be using the variable in a particular way, e.g. according to one of the four "fundamental" Perl types. There are four Perl sigils: $ for scalars, @ for arrays, % for hashes, and & for code.

The sigil is a part of the name of the variable -- they're always used together. Because of this, you can even have different variables that have the same name, except for different sigils:

$foo      # all these point to different variables
@foo
%foo
&foo;

Naming Variables: Variable names must always start with a sigil, and may contain only alphanumeric characters (including Unicode characters!) and the underline character, _. The only other major restriction on variable names is that the first letter after the sigil must not be numeric -- otherwise, it would be hard for Perl to identify which things were variables, and which things were expressions.

The following are all valid variable names:

$foo
$foo_
$_bar_
$__my__long__winded__var__
%my_hash
$thing_01
$t85
@array
$_1_
but these are not:
$1_var       # WRONG, starts with a numeric character
$foo$        # WRONG, ends with a non-alphanumeric character
^var         # WRONG, ^ is not one of the four valid sigils

Scope: Variables also have a scope: that is, a specific region of the program in which they are visible. When a variable can be seen from anywhere within the program, it is called global. When a variable can only be seen from within a certain area of the program, it is called lexical. (You may also run into the term lexically scoped globals, which basically means lexical, but with a broader scope than most lexicals.) Truly global variables are generally avoided whenever possible, because it's easy to clutter up the global namespace with variables that most of the program doesn't need, and (worse) it's very easy for two separate parts of the program to, accidentally, pick the same variable name to do two different things, creating bugs that can be very difficult to find.

There are three major scope declarators that you will use in Perl:

  • my $var declares a variable named $var to have lexical (limited) scope, typically visible only within the surrounding code block. This may override some other declaration of $var, meaning that if you already have a variable named $var, the statement my $var will create another, separate one, hiding the older definition.

  • our $var declares a lexical variable $var that is available anywhere within the scope of the current package or module (e.g. a lexically scoped global). our is different from my in that it doesn't actually "create" the variable -- it just "refers" to it, under the assumption that it already exists (though if it really doesn't exist, it will make it for you.) Thus, if you say our $var multiple times, you aren't actually creating multiple variables named $var: you're just referring to the same $var, over and over again.

  • temp $var is special. It declares a variable named $var that is dynamically scoped, meaning that it temporarily hides (until the end of the enclosing block) any other declaration of $var that has previously occurred. This is true even if you enter another scope from within your block (for example, if you call a subroutine, or if that subroutine calls another subroutine, etc.) temp is a runtime phenomenon -- the "hiding" happens during runtime, and not during compilation, as with my and our.

We'll describe the usage of my, our, and temp in more detail later. First, let's describe how you use variables and values in general.

Declaring Variables and Assigning Values

Now let's look at a very small, very basic Perl statement.

my int $i = 5;
This statement delares a new lexical variable named $i, which can only store values with the data type int. It then assigns the literal value 5 as the initial value of the variable. There are several things going on here, so we'll break it down into even smaller pieces.

my $i;

This statement, as we saw in the last section, simply declares a new lexical variable named $i. The sigil $ marks that the variable may only contain scalar values, not arrays, hashes, or actual code (though it could contain a reference to any of those things -- more on that a bit later.) We're not declaring what specific scalar type the variable may contain, however, so it will happily accept any scalar value we assign to it. This can be useful in some situations, but it is typically helpful to declare that the variable will contain a specific type -- that will allow Perl to do some compile-time checking to make sure you're always using the variable in the way you really intended to.

The next statement associates a specific data type with the new lexical variable $i. Note that int is declaring the data type that the variable may contain, not the type that will implement the variable (yes, you can specify that, too!)

my int $i;
The int part declares that you will only be putting integer values into $i. If you try to place some other type of value into $i, it will attempt to convert the value to an integer. If it can, it will place the new, integer value into the variable. If it can't, it will generate an exception, warning you of the fact.

my int $i = 5;

The = character is the assignment operator: it assigns the value on the right side to the variable on the left side. The above statement, therefore, not only declares the scope and type of the new variable $i, but assigns the value 5 to it. Note specifically that the int part doesn't refer to the 5 -- it refers to the container type of the variable, as we saw above.

It just so happens that the literal value 5 is trivially an integer. If we tried to put some other value inside the variable, it would either be put in as an integer, or an exception would occur:

$i = 5;       # OK
$i = 2 + 3;   # OK: (2 + 3) resolves to the value 5, an int
$i = "5";     # OK: string 5 can be converted to integer 5
$i = "five";  # WRONG, string "five" can't be converted to an int
$i = 5.05;    # OK: floating point 5.05 will be truncated to int 5?
$i = $k;      # depends on whether $k can be converted to an int

This happens because Perl knows that $i is declared to be an int, and so always evaluates assignments to $i in int context. Also note that (unless you're assigning a reference to a value) all these conversions take place on a copy of the value you place, not the value itself, so the original value remains untouched. The value of $k in the last example is not modified -- it's still whatever it was before.

Context

We've stated that a value may be converted to a value of another type based on the context in which it appears. Now let's formalize the notion of context more completely.

Context refers to the type of value that Perl expects to use in any given situation. For example, a conditional statement like:

if $var { ... }
expects to operate on a boolean value (either true or false.) If the tested condition is true, the code inside the { ... } block will be executed; otherwise, it won't be. In order to use the variable $var inside an if statement, therefore, the value of $var must be used in boolean context -- it must be convertable to a boolean, and it is that boolean value which will then be tested by the if statement.

Similarly, if you are adding two values together:

$var1 + $var2
you are operating in numeric context. Since the operator + expects to treat both sides as numbers, both $var1 and $var2 are evaluated in numeric context -- that is, converted to numbers -- before the addition of those numbers can take place.

If you print a variable or value, you are using string context:

print $var;    # 'print' expects to see a string
so the value of $var is converted to a string, if possible.

In a nutshell, that's all that is meant by the notion of context. Context is just the data type that is expected, as opposed to the data type the current value actually is. There is, not surprisingly, a context for every type that exists in perl:

  • Scalar context means that a scalar value is expected.
  • Array context means that an array is expected.
  • Hash context means that a hash is expected.
  • Code context means that a block of executable code is expected.
... and each of those "primary" contexts encompasses a great many more specific contexts that match every possible Perl type. For example, boolean context, numeric context and string context are considered subclassifications of scalar context, so if you make a statement like:
$var1 + $var2
$var1 and $var2 are considered to be both in numeric context, and in scalar context.

Void Context: There is one other context, called void context, that represents that no data type at all is expected -- if one is provided, it would simply be thrown away. For example:

my int $i = 5;    # 5 is in integer context
5;                # 5 is in void context
                  # (we're not doing anything with it)
This is especially useful when declaring functions or methods, where you can check to see what context your function is being called in -- if it's void context, you know that the caller is just going to throw your return value away. Maybe that means you shouldn't bother calculating a return value in those cases, or maybe it even means you should throw an exception, to vigorously warn the caller that not checking your return value is an exceptionally bad idea.

Most of the time, you won't be worrying about the context, since Perl will convert values from the current type to the required contextual type automatically, as long as it can find a way to do so. There are occasions, however, where you explicitly want to treat a variable or value as being in a certain context. You can do this through typecasting.

Typecasting

Typecasting is the conversion from a value of one type to a value of another type. In Perl, typecasting happens automatically in most situations. For those occasions when you specifically want a value to be evaluated in a way different from what the context of the value implies, you can use an explicit typecast by specifying a type name before the value:

str 5;           # convert the value 5 into the string value '5'
int "10.0";      # convert the string "10.0" into the integer 10
scalar @mylist;  # convert the array value of @mylist into a scalar
                 #  (returns the number of elements in @mylist)
bool $myObject;  # convert value of $myObject into a boolean (1 or 0)
The typecasting syntax is type expression or type(expression), so you may typecast the value returned by any expression, not just simple terms like the above. Note that typecasting returns a value of the requested type, but it doesn't change the value of the thing it's operating on -- in the last example, the variable $myObject isn't altered. If the value is already the requested type, the statement is a noop -- an operation that doesn't do anything at all.

You generally use typecasting to force the context in which a value or expression is evaluated. For example:

print @list;          # prints all values inside @list
print scalar @list;   # prints the 'scalar' value of list,
                      # e.g. the number of elements

Not all typecasts are possible: that is, values can't necessarily be converted from one type into every other possible type. In general, Perl's builtin types have all the most useful conversions predefined, but if you're attempting to typecast to or from your own object classes, you'll first have to set your classes up to support those typecasts.

Perl will always look for the "best" translation between typed values, but if no possible translation exists, an exception will be thrown.

Binding (Aliasing) Variables

Binding is different from assignment. While assignment copies the value of whatever's on the right side, and places it in the variable on the left side, binding makes variable on the left side point to the same "container" as the variable on the right side. The binding operator is :=.

my $a = 5;
my $b := $a;     # $b now points to the same thing as $a
If the variable on the right side changes in value, the variable on the left side will change, too:
$a = 10;
print $a;    # prints "10"
print $b;    # prints "10";
This has the practical effect of making the variable $b an alias for the variable $a. As we will see later, the list form of binding is especially useful, since it allows you to swap the contents of variables:
($a,$b) := ($b,$a);   # $a now contains what was previously in $b,
                      # $b now contains what was previously in $a

(@a,@b) := (@b,@a);   # works for lists and other data types, too!

Properties

(mjl-- I don't think this section even needs to be here. May want to delay property introductions until later.)

Values and variables may also have properties attached to them, which are essentially "out-of-band" notes on how the value or variable should behave. They don't change what the value or variable is, they just change how it will act.

Properties on variables are frequently called compiletime or fixed properties, because they are a part of the declaration of the variable: you can't change them afterwards. Fixed properties are declared using the keyword is. Examples would include:

my $var is private = $somevalue;  # declaring a private variable

Properties on values are called runtime or dynamic properties, because they may change at runtime. Dynamic properties are assigned using the keyword but. The most useful builtin dynamic properties are probably true and false, but there are others.

my $var = 5 but false; # the value 5, but evals to
                       #     'false' in bool context
my $var = 0 but true;  # the value 0, but evals to
                       #     'true' in bool context
You can also define your own fixed and dynamic properties. We'll explain the details in later chapters: for now, just be aware that properties can exist.


Builtin Scalar Types

Perl has the following builtin scalar types. Some types have two names: the first refers to the primitive type, which is what you will use most of the time. The second name is the promoted type, or full object type: this is the name for a larger version of the object that may have associated methods, properties, and other object-oriented accoutrements. Don't worry about the promoted type names just yet, we'll get to them later.

[primitive]   [object]
               Scalar    - the root for all scalar types
   bool        Bool      - a boolean (true or false) value
   bit         Bit       - a single bit, with the value 1 or 0
   int         Int       - an integer
   num         Num       - a floating point number
   str         Str       - a string
   ref         Ref       - a reference
               Rule      - a rule, e.g. a regular expression
               Code      - executable code
               Class     - the definition of a declared class
               Object    - an object

Declaring Scalars: To declare a scalar variable, use the $ sigil. You may also give a specific type, if you wish:

my      $i = 10.05;     # no type given, but 10.05
                        #   is assumed to be a num
my int  $i = 10;        # integer value
my bool $t = 1;         # boolean value
my str  $s = "Hello!";  # string value

Boolean Types, bool and Bool

The bool type is a boolean -- a fundamental unit of logic that represents only two possible values, true and false. Boolean values are used quite extensively in Perl: whenever you make a conditional statement like if or unless, or are looping on a tested condition, such as while $v { ... }, you're testing a value to see if it's true or false, and performing some action based on that. The bool type is useful for storing the "truth" of an expression, instead of the "value" of the expression -- for example, the result of a comparision.

my bool $lit = ($lights eq 'on');

if $lit {
    # ... do something ...
}
Boolean values and variables are extremely compact and efficient, so if you're defining a variable, and you know that the value of it will never be anything other than true or false, you should make it a boolean:
my bool $light_switch;      # on or off
my bool $is_correct = 1;    # true or false
my bool $has_a_tail;        # yes or no
Note that we didn't give an initial value to two of the above statements. A bool that is not specifically true is always assumed to be false, so the above is equivalent to:
my bool $light_switch = 0;    # on or off
my bool $is_correct   = 1;    # true or false
my bool $has_a_tail   = 0;    # yes or no

A primitive type like a bool can never be undefined -- it is always 1 or 0. If you explicitly set a boolean variable to the undefined value:

my bool $t = undef;
the variable is automatically set to 0. If you don't want this behavior, you can use the promoted boolean type, Bool. A Bool value can be undefined:
my Bool $has_a_tail;   # undefined, until set to something else

$has_a_tail = 1;      # now it's true
$has_a_tail = 0;      # now it's false
$has_a_tail = undef;  # now it's undefined again
Because promoted types like Bool are slightly larger and slower than their primitive counterparts like bool, you should get in the habit of using the primitive varieties whenever possible, and only using the promoted types when that's what you really mean.

What is Truth?: The notions of true and false are fairly liberal in Perl. In general, any scalar value is considered true except for the following:

0       # any numeric value equal to zero
   "0"      # the exact string "0"
   ""       # the empty string, ""
  undef     # the undefined value
Perl allows any value to be true or false however. You can attach but true or but false declarations to any value to specifically enforce the "truth" of that particular value.
0;             # usually false
    0 but true;    # true
    1;             # usually true
    1 but false;   # false
  "0";             # usually false
  "0" but true;    # true
Note that the bool type and the bit type that we will introduce later are therefore not synonymous, and may not be used interchangeably. A bit is a numeric type that stores an integer value, 1 or 0: it corresponds to a single computer "bit". A bool stores conceptual truth or falseness. Unlike many other languages, Perl allows a 0 value (usually considered false) to sometimes be true, and a 1 value (usually true) to be false! This usage is typically quite rare, but if you are ever given a value that is "0 but true", or "1 but false", you'll want to very clearly distinguish between the value (1 or 0) and the boolean truth (true or false). So use bool when you mean truth, and bit when you mean a numeric 1 or 0.

Typecasting Between bool and Other Types: bool values may be trivially converted to numeric and string types. In numeric context, a boolean value is represented by the integers 1 or 0. In string context, a boolean value is represented by the strings "1" or "0".

Boolean Operators: A number of operators exist in Perl for manipulating boolean values. We'll explain them more fully in a later chapter, but these are the most common ones:

# Binary Operators
   
    $a && $b;   # logical 'and'  (high precedence versions)
    $a || $b;   # logical 'or'
    $a ^^ $b;   # logical 'xor'
   
   $a and $b;   # logical 'and'  (low precedence versions)
   $a  or $b;   # logical 'or'
   $a xor $b;   # logical 'xor'
   
   # Unary Operators
   
      ?$a;    # cast $a to a bool, if not one already
     !?$a;    # cast $a to a bool, negate
   not $a;    # cast $a to a bool, negate
For more details, see the chapter on Operators.

Numeric Types

The primary numeric types in Perl are int and num, which represent integers and floating point numbers, respectively.

my int $i = 0;      # integer
my num $v = 12.5;   # floating point
If you don't assign a value to an int or num, it defaults to the value 0. Like all primitive types, you cannot set them to the undefined value, undef. If that's a problem, you should use their equivalent promoted types, Int and Num.

Literal Numbers: Literal numbers in Perl can be expressed in a variety of ways. Perl understands decimal, scientific, binary, octal, and hexidecimal representations of numbers, as well as Inf and NaN.

123         (decimal)
   0123         (decimal)
   -123         (negative, decimal)
123456000.000   (floating point)

  0b01101000    (binary)
  0c123         (octal)
  0xff88ee      (hexidecimal)
  0xFF88EE      (hexidecimal)
    
-123.004        (negative, floating point)
 123456.7       (floating point)
  12e10         (scientific/exponential notation)
 -5.33E2        (scientific/exponential notation)

    Inf         (positive infinity)
   +Inf         (positive infinity)
   -Inf         (negative infinity)
    NaN         (not a number)
The terms +Inf and -Inf represent positive and negative infinity; you may sometimes use these to create infinite lists. The value NaN ("Not a Number") may be returned by some functions or operations to represent that the result of a calculation (for example, division by zero) cannot be represented by a numeric value.

Perl allows the underline character, _, to be placed as a separator between the digits of any literal number. You can use this to break up long numbers into more readable forms. There aren't any rules to it; you can use it however you like:

123_456_000.000   (floating point)
 0b_0110_1000     (binary)
 0xFF_88_EE       (hexidecimal)
-5.33_E2          (scientific/exponential notation)
You can even specify numbers using a base other than the usual 10, 2, 8, or 16 by specifying an explicit radix before the number, using a colon:
10:123       -- same as 123 decimal
 2:1101      -- same as 0b1101
16:ffEE      -- same as 0xffEE
55:5Ffkz8j   -- base 55, uses both lowercase and uppercase letters
Note that you can specify hexidecimal (base 16) values (and values in any other base lower than 37) using either uppercase or lowercase A-F. This is because Perl uses the following digit mappings when using non-standard radix specifications:
[radix]  [    characters used    ]
            [0 - 9]  [10-35]  [36-61]
    2..10     0..9
   11..36     0..9  'a'..'z' ('A'..'Z' assumed identical to 'a'..'z')
   37..62     0..9  'a'..'z'  'A'..'Z'
You cannot specify a radix above 62, because Perl wouldn't have enough alphanumeric characters to represent it. You'd have to program something like that on your own.

Assigning Values to Numeric Types: When typing a literal number like any of the above, you generally don't specify the exact type of the number, because Perl can determine it from the surrounding context. When you state a literal number in a context where Perl can't be sure what numeric type you intend to create, Perl will usually create the number as a num. If you're using the literal value in a context that expects to a certain type, however, it will be interpreted as that particular type.

my $n     = 12;   # 12 is treated as a num
my num $n = 12;   # 12 is treated as a num
my int $n = 12;   # 12 is treated as an int
How you write a literal number doesn't affect the type of the number. You can write a literal number in any format you wish, it will still be treated as whatever type the context dictates. That's why you can specify:
my int $n = 1.2E1;
my int $n = 0b1100;
my int $n = 0c14;
my int $n = 0xc;
and $n will be assigned the integer value 12 in each case. Format does not affect type!

Converting Between Numeric Types: Perl performs automatic conversion between all numeric types, so you can easily convert numbers from one type to any other type.

my int $n = 5;      # $n is the integer value 5
my num $x = $n;     # now $x is now the floating point value 5.0

my num $x = num 5;  # typecast 5 to num, assign to num $x
my num $x = int 5;  # typecast 5 to int, then automatically
                    # to num in order to assign it to num $x
There are two things to be aware of. First, if you try to assign a non-integer value to an int:
my int $n = 5.95;         # sets $n to 5
my int $n = int 5.95;     # ditto
the value will be truncated to an integer. If you intended to round the number, you should do it explicitly:
my int $n = round 5.95;   # sets $n to 6
Second, the conversion will only work if the destination type can handle a number in the range you've specified. If not, the number may be truncated or rounded to fit, or an exception may be thrown, depending on how that numeric type has been designed to deal with the situation. In general, however, you only have to worry about this when using very big, very small, or very, very precise floating point numbers.

Typecasting Between Numeric and Other Scalar Types: A numeric value may trivially converted to a boolean or string value simply by using it as such.

When typecasting to a bool, any numeric value that is not 0 is assumed to be true:

0     # false
   0.00  # false
   23    # true
When typecasting to a string, the value is always represented in integer, decimal, or exponential form, depending on how the number can best be represented:
print 5;     # is integer value, so prints "5";
   print 5.0;   # is integer value, so prints "5";
   print 5.1;   # is float value, so prints "5.1";
   print 2e33;  # is very big number, so prints "2E33";
(mjl -- need specific rules for deciding what "big" is in casting to string)

If you want to output a number as a hexidecimal or another specialized format, use sprintf or one of the other formatted output functions, or create your own numeric type that converts to and from strings according to your own preferences.

Numeric Operators: There are a large number of operators in Perl that are designed to work with numeric values. We'll explain the Perl operators more fully in a later chapter, but these are the ones that are most common when working with numeric values. You will recognize most of them as being identical to those in C or other languages:

# Unary Operators
   
   +$a;   # cast $a to a number, if not one already
   -$a;   # cast $a to a num, negate
   
   # Arithmetic Operators:
   
   $a + $b;   # addition
   $a - $b;   # subtraction
   $a * $b;   # multiplication
   $a / $b;   # division
   $a % $b;   # modulo (remainder)
   $a ** $b;  # exponent
   
   # Prefix/Postfix Operators
   
   ++$a;      # preincrement $a
   --$a;      # predecrement $a
   $a++;      # postincrement $a
   $a--;      # postdecrement $a
   
   # Comparision Operators
   
   $a == $b;   # equal to
   $a >  $b;   # greater than
   $a <  $b;   # less than
   $a <= $b;   # greater than or equal to
   $a >= $b;   # less than or equal to
   
   # Bitwise Operators
   
   ^$a;        # one's complement of $a, e.g. ($a +^ 1)
   $a +& $b;   # bitwise 'and'
   $a +| $b;   # bitwise 'or'
   $a +^ $b;   # bitwise 'xor'
   $a >> $b;   # shift right
   $a << $b;   # shift left
For more details, see the chapter on Operators.

Overflow and Out-Of-Range Errors: If you attempt to assign to a typed numeric variable a value that is too big to be represented in that type, Perl only has two choices: truncate the value so that it fits, or generate an exception warning you that the value doesn't fit.

... (mjl -- so which is it?) ...

Precision: Perl uses double-precision floating point numbers (frequently just called doubles) to represent the num type. If you've worked with floating point numbers in languages like C, you know that while they are very precise, but they aren't infinitely precise. There's no way to exactly represent a value like 1/3 or 1/7, and even simple rational values like 1.1 aren't necessarily represented exactly by a double, because of the way floating point values are represented internally by the computer. They are, by design, estimations that fit in 64 bits of memory. They're very, very close estimations, mind you, but not exact: rounding errors inevitably occur.

(mjl -- Note: probably should put a sidebar explaining float internals here.)

What this essentially means that it's generally a bad idea to compare two floating point numbers for equality. (If you've been programming with floating point numbers in other programming languages, you probably already knew that.)

(10*(1/3) == (1/3)*10)    # FALSE, due to rounding errors.  Oops!
The correct way to compare two floating point numbers is to ask if they are within a desired range of one another. Specify a range that's small enough to accomplish your required degree of precision, but still large enough not to run into the precision boundaries of floating point representations:
(abs(10*(1/3) - (1/3)*10)) < 0.00001)  # TRUE, like it should be
None of these problems come up when you are simply testing floating point numbers to determine if one is greater than or less than another (unless your numbers are larger or smaller than floating point can represent, of course), only when testing for equality.

Promoted Types: Ints and Nums: The promoted types of int and num are Int and Num. The promoted types are larger and somewhat slower than their primitives, but have significant advantages:

  • They will automatically use BigInt and BigRat representations when needed, to dramatically improve the range and precision of the numbers they can store.
  • They may be given associated properties.
  • They may be set to the undefined value, undef.
The promoted numeric types are therefore very helpful when working in some situations. Because they're not as efficient as their primitive counterparts, you should only use them when you expect to need their added capabilities.

The Full List of Numeric Types: In addition to the standard int and num, there are a great number of other numeric types available. If your program makes use of code written in other languages, such as C, C++, Java, C#, etc., or if you want your program to make use of low-level system or library calls, you will frequently need to use more exact types that correspond to what the other language expects to see. You might also wish to use the more specific primitive types when you can guarantee certain bounds restrictions on numbers, and simply want to squeeze every unnecessary byte out of the generated code.

# (TEMPORARY) need final list of numeric types & any aliased names,
# assuming we don't want to support *all* of these names (tho we could)
# the base numeric type

numeric

# signed integers

int
int8     char
int16    short      short_int
int32    long       long_int
int64    quad       long_long    long_long_int

# unsigned integers

bit
uint     u_int
uint8    u_int8     u_char    byte
uint16   u_int16    u_short   u_short_int
uint32   u_int32    u_long    u_long_int
uint64   u_int64    u_quad    u_long_long    u_long_long_int

# floating point numbers

num
float
double
long_double

Each of these has a matching promoted type, which starts with a capital letter instead of a lowercase letter (e.g. Int vs. int, Num vs. num.)

The bit type is special; unsurprisingly, it represents a single computer bit: a value that may contain only 1 or 0. Note that as we mentioned earlier, a bit is very different from bool. A bit stores an integer value, 1 or 0. A bool stores conceptual truth or falseness. Those aren't always the same things.

You typically won't declare anything as the numeric type: it's just a base class for all the others. You can create your own types based on numeric or any of the other standard types; more on that in later chapters.

The String Type

(mjl -- more coming soon!)


Login / Edit User Info -- Copyright © 2002 Cognitivity -- Previous Page   Next Page