A Beginners Guide To Euphoria

Variables And Data Objects

We mentioned previously that a program will store data for analysis. Your computer's memory (RAM) best resembles a huge group of mail boxes, each of which is uniquely addressed by a number. Each of these storage locations can hold a value between 0 and 255. Each of these values is referred to as a "byte". If values over 255 need to be stored in RAM, it is split up between various locations. While data is always stored as numbers in RAM, it can be both numeric or characters like "A". To write a program that accesses RAM locations by address number would be tedious, especially when dealing with large data values. Thankfully, Euphoria offers a way to access stored data in RAM not by the actual RAM address number, but by a label like "salary" or "points". This symbolically referenced memory location is called a "variable".

Variables are invaluable for two reasons. First of all, it's much easier to know where all your data is located in your program if you use meaningful names. For example, if you are writing a space combat game and want to store data representing the amount of fuel you have left in your ship, storing it in a variable called "fuel" makes it so much easier to find than some obscure RAM memory address like 32767. In addition, because a variable holds a single stored value regardless of its size, there's no complex handling of multiple RAM locations when dealing with very large values. Euphoria does this for you behind the scenes. When it comes time to compile or interpret your program to be run, variable names are converted automatically to actual RAM memory addresses. But that is something a Euphoria programmer does not need to be concerned about.

Variable names can be any length in size, and can both be real words or made up ones that border on nonsense, as long as the name itself is meaningful to the programmer. However, Euphoria does place some limits on what you can use for a variable name. First of all, variable names must start with a letter and then can be followed by any combination of letters, numbers and the underscore ("_"). Second, case is significant. This means the variable name "tax" is not the same as "TAX". Finally, words used in the Euphoria language cannot be used as a variable name. They include, but are not limited to, words like "and", "global", "function", "while", and "exit". These words are called "reserved words". A complete list can be found in the Euphoria Reference Manual. Now that we have completed our understanding of variables, let's move on to learn about the type of data we can store inside a variable.

In Euphoria, all data is referred to as "data objects". The reason this term is used to describe data is because data isn't something you work out in arithmetic calculations. Instead, data in Euphoria is viewed as tangible items you can merge together, break apart, twist, or alter at the slightest whim. As we go further into understanding the Euphoria language, you will soon see this to be true. Data objects come in two types. The first type is the atom, which is a single numeric value. Below are examples of atoms:
 
                 2001    12.4    -5    3.14e3
 
The first three examples are very familiar to all of us, but the fourth is an example of Standard Notation. The "e" means "times 10 to the power of", with the number following. This means 3.14e3 is really 3.14 times 10 to the power of 3, which works out to 3140. Standard notation is best used to represent atom values in a compact form. Atoms can either be a floating point (with a decimal point) or integer value (no decimal point) value, and can be either positive or negative. Atoms can have a value range of approximately between -1e300 and +1e300 (that's -1 followed by 300 zeros to 1 followd by 300 zeros, inclusive). While chances are good you will never design a program that handles such huge numbers, it is nice to have that wide a margin to work with. The second type of data object is called a sequence, and is a little more complex in structure. Sequences are a list of data objects joined in the same manner as links on a chain. Each linked data object is referred to as an  "element". Sequences can be made up of either atoms, smaller sequences, or any mixing of both. You can have sequences inside of sequences, which in turn are part of bigger sequences, and so on, to any level of dimension. Computer memory is the only limiting factor. Sequences always start with a "{", have commas or "," separating each individual data object, and a closing "}". Here are some examples of sequences:

  A sequence made up of atoms:     {2,4,6,8,10}

  A sequence that is made up of three smaller sequences:
       {{31,32,33,34,35},{41,42,43},{51,52,53,54,55,56}}

  namely  {31,32,33,34,35}, {41,42,43} and {51,52,53,54,55,56}.

  A sequence that is made up of both an atom and two  sequences:
       {{100,101,102},200,{301,302,{-401,-402},303}}

  namely {100,101,102},200 and {301,302,{-401,-402},303}.

Notice that the third sequence example has a sequence within a sequence as the third element. Sequences can be represented in the form of a character string, like the text you are reading now. Character strings begin with a quotation mark followed by any numbers, letters or special characters, then ended with a second quotation mark. The character string is translated by Euphoria to the sequence's real form automatically. For example, the following two values:

        "David Alan Gay"

        {68,97,118,105,100,32,65,108,97,110,32,71,97,121}

are identical in value. They only differ in the way they are presented. The numbers in the second value are the ASCII codes of each character. ASCII is a convention that assigns each character, displayable or not, a numeric code. This convention was created to ensure that all computers, no matter who made them, will display data the same way. ASCII stands for American Standard Code for Information Interchange.

Character strings are best used to define sequences that are to be used for display on a screen or printer, such as names, addresses, etc. If you are feeling a little overwhelmed by all these terms, like "variables", "data objects", "atoms", and "sequences", don't be alarmed. It's because you haven't had the chance to see how they work in Euphoria. That will now change. You will now be introduced to your first Euphoria programming statements, by learning how to create variables for your program to use later.

ToC

Declaring Variables In Euphoria
 
Before using variables in Euphoria, you first must "declare" them. Declaring a variable is similiar to declaring items in front of a customs officer. When you declare items, you tell the officer what they are, what type of items they are and so forth. In Euphoria, declaring variables in a program involves two things: stating what they are going to be named, and defining the type of data they are supposed to hold. To declare a variable in Euphoria, you use the following syntax:

        variable type variable name

variable type means the type of data object the variable will hold.  variable name means the name of the variable, of course. The first part of the variable declaration, the variable type, comes in only four accepted words: "sequence", "atom", "object", and "integer". "sequence" means the variable can only hold data objects that are sequences. You cannot place atom data objects in this type of variable. "atom" means the variable can only hold data objects that are atoms. Sequences are not allowed. A variable type of "object" means the variable can hold both atom and sequence data objects. One must wonder why we bother having variables of type atom and type sequence when a type object variable can hold both. Type object variables are needed to hold the result of program data processing where the data type is unknown. "integer" means the variable can hold atoms, but only integer atoms. An integer atom can have a value between -1073741824 and 1073741823. If you want to use even larger integer in your programs, you need to use the type atom variables to hold them.

Variable declarations usually appear at the top of the program, so they are one of the first things typed in by the programmer. However, there are exceptions where they may appear elsewhere in the program. A variable declaration is entered only once for every variable in the program. Once entered, you cannot enter a second variable declaration using the same variable name, even if the variable type is different. Let's start entering our very first Euphoria statements. To declare a variable named "address" that holds sequence type data objects, we enter:

        sequence address

To declare a variable named "age" that holds atom data objects we enter:

        atom age

To declare a variable named "grab_bag" that can hold both atoms and sequences, we enter:

        object grab_bag

to declare a variable named "Whole_Numbers" that can hold integer atoms between -1073741824 and 1073741823, we enter:

        integer whole_numbers

When dealing many variables of the same type, you can declare them all with one variable type followed by a series of variable names. For example:

        sequence name, address, city, country

will just as easily declare these four variables as if you used a single declaration line for each variable. If you wanted to get really fancy, this is also a legal way to declare multiple variables:

        atom hours_worked,
             hourly_rate,
             deductions,
             net_income
 
Euphoria offers the ability to split variable declarations (and other types of statements) into several lines as opposed to one line. Just remember the commas, and only split the line where there is a space. Having a variable type as part of a variable declaration is a kind of safety system. It prevents a programmer from entering the wrong type of value into a variable. It also ensures that certain features of the Euphoria programming language that are meant to work on one data type do not get slipped with a variable value that is of a different  data object type. Which brings us next to the topic of variable values. Is there an initial value placed inside a variable after it is declared? The answer is no. Don't get the impression, however, that there is nothing inside a variable. Most likely it is left-over data from a previous program run, and probably so garbled that it is unusable. For this reason, Euphoria rules dictate that a programmer must place a value inside a variable for the first time before it can be used. The next few chapters will discuss the process of initializing variables with values, and even changing those values. This is an important part of Euphoria that must be clearly understood, because it involves the primary purpose of all programs, which is to process data.

ToC

Assigning Values To Atom Variables, Part One

This chapter begins the topic of placing values in atom variables. But first, an important note. Even though this chapter uses atom variables in the examples, what you learn here also pertains to object type variables. You can also use integer variables, but remember that integer variables only hold positive and negative whole numbers. To place values in atom (and in other types of) variables, you use an "assignment statement". The concept of assignment statements is really quite easy to follow. Here is the syntax of the assignment statement listed below:
 
     variable = expression

variable is of course, a variable. The equal sign means "is given the value of". expression is either a constant value, another variable, or a complex formula. An expression is evaluated to a single value, which is then stored in the variable to the left of the equal sign. Let's begin with a simple example of assigning a variable with a value:
 
     atom year, copy_of_year
     year = 1997
     copy_of_year = year

(Author's note: first, you could say the above is a simple example of a program, and second, from this time forth, any examples involving Euphoria will always show the appropriate variables declared.) In the example on the previous page, the atom variable "year" is being assigned a value of 1997. The value 1997 is the simplest example of an expression, as it is already a value of 1997. The variable "copy_of_year" is given a value of what was just placed in "year". Euphoria checks to see what is inside "year", and then places that value in variable "copy_of_year", which is 1997.

     atom letter_of_the_alphabet
     letter_of_the_alphabet = 'C'

In the example above, the variable, "letter_of_the_alphabet" is being assigned a numeric value, but the numeric value is represented here as a character between single quotes or '. This character representation is evaluated into the numeric ASCII value of the letter C. This means "letter_of_the_alphabet" ends up containing a value of 67. Here's another way to assign an atom variable with a numeric value: 

     atom double_quotation_mark
     double_quotation_mark = '\"'
 
This example program places the ASCII value of a double quotation mark in variable "double_quotation_mark", which is 34. It works just like the previous example that used a character representation of a numeric value. This form of expression is commonly used for special characters that cannot be entered by keyboard, or to use Euphoria symbols like the for output. Other examples of \-prefixed special characters include \n for new line, \t for tab, and \\ for reverse slash. A complete list of these special characters is explained in the Euphoria Reference Manual. But expressions can also be more than just a special representation of a single value. They can be the result of very complex arithmetic calculations. In this case, expressions are a combination of numbers, other variables, and special arithmetic operators. In Euphoria, the following symbols listed below are arithmetic operators:
 
     +       addition
 
     -        subtraction

     *        multiplication
 
     /         division
 
Let's put these operators to use in the program example on the following page. Here is a program example that works out the amount of tax paid and the
total cost of a pair of jeans.
 
   atom jeans, tax, tax_paid, total_cost
   jeans = 22.00
   tax = .07
   tax_paid = jeans * tax
   total_cost = jeans + tax_paid

Variable "jeans" represents the sale price of a pair of jeans, so we assign it a value of 22.00 (with decimal points to look like dollars). variable "tax" is then assigned a value of 7%, which is 0.07. Next, variable "tax_paid" is computed by multiplying the values of variables "jeans" and "tax" together. Finally, variable "total_cost" is assigned the sum of the values stored in "tax_paid" and "jeans". The previous program examples have all shown variables being initialized for the first time, and only once. What happens if a variable already contained a value, but was assigned a new value? Well, the old value of the variable would be replaced with the new value. A variable may only hold one value at any time. But this shouldn't be considered a problem, as variable value modification is just as important as initialization. Note the following example:
 
   atom counter
   counter = 0
   counter = counter + 1
   counter = counter + 1
   counter = counter + 1
 
What is the value of variable "counter" after this program finishes? Let's look at the program again, this time examining it line by line:
 
   atom counter
   counter = 0                -- "counter" is initialized to 0
   counter = counter + 1      -- "counter"'s value is now 1, by adding 1 to 0
   counter = counter + 1      -- "counter"'s value is now 2, by adding 1 to 1
   counter = counter + 1      -- "counter"'s value is now 3, by adding 1 to 2

After variable "counter" is set to zero, its old value is replaced with a new one in the next 3 lines, by taking the original value and adding 1 to it to produce a new value. This is done three times in the program example. An introduction to relational and logical expressions is our next stop!

ToC

Assigning Values To Atom Variables, Part Two

Continuing our discussion of assigning atom variables with values, we now introduce relational and logical expressions. Relational means based on comparison. For example, you can be taller than one person, yet shorter than another. Your parents are older than you, yet at the same time, you are older than your children or younger siblings. It works the same way in Euphoria. Is one variable value larger or smaller than an expected value? Is this value equal or unequal in a comparison with another value? Relational expressions are evaluated to one of two values: 1 for true, or 0 for false. Here are a list of valid Euphoria relational operators:
 
  <    less than
  >    greater than                              
  <=  less than or equal to
  >=  greater than or equal to          
  =    equal to
  !=   not equal to                                
 
Here is a program example that uses several of these operators in relational expressions. See if you can guess the value of each variable first before reading the explanation of each line:
 
   atom t1, t2, t3, t4
   t1 = 5 > 4              --1 (TRUE) in "t1": 5 is GREATER than 4
   t2 = 7 != 7             --0 (FALSE) in "t2": 7 is EQUAL to 7, not UNEQUAL
   t3 = 13 <= 13           --1 (TRUE) in "t3": 13 is LESS THAN OR EQUAL to 13
   t4 = 12 = 2 * 6         --1 (TRUE) in "t4": 12 is EQUAL to 2 * 6, which is 12

Logical expressions focus more on whether a given situation is true or false. For example, if one says, "The bedroom light is switched on", the statement is either true (the light is indeed switched on), or false (the light is not switched on). The analysis of the truth of a situation can be more complex than the bedroom light example. For instance, the handling of delinquent accounts at a loans company requires more than one condition to be met. First of all, the account must be in a state of not being paid. Second, it must be in that state for a given set of time before the customer is called. Both of these conditions must be true before an account is considered delinquent (the given situation is true). If any one of the conditions are not met, then the account cannot be delinquent (the given situation
is false). Euphoria has logical operators that work using a system called BOOLEAN LOGIC. This system dictates that the outcome of paired conditions, either
single values or relational expressions, are based on the rules below:
 
Condition 1          Condition 2   Result
1 (true) and   1 (true)   1 (true)
0 (false) and   1 (true)   0 (false)
1 (true) and   0 (false)   0 (false)
0 (false) and   0 (false)   0 (false)
1 (true) or   1 (true)   1 (true)
0 (false) or   1 (true)   1 (true)
1 (true) or   0 (false)   1 (true)
0 (false) or   0 (false)   0 (false)
 
An "and" logical expression only evaluates to a single true value if both conditions are themselves evaluated to be true, and an "or" logical expression is only false when both conditions are false. So let's put this knowledge to use in an example Euphoria program:

   atom value1,value2,test1,test2,test3,test4
   value1 = 50
   value2 = 25
   test1 = value1 < 10 and value2 = 25
   test2 = value1 > 5 and value2 = 12.5 * 2
   test3 = value1 != 100 or value2 < 90
   test4 = value1 = 5 or value2 > 27

Try to guess the value of each variable before going to the next page.

   value1 = 50
   value2 = 25
   test1 = value1 < 10 and value2 = 25

Because variable "value1" is not smaller than 10, the first relational expression is false. Variable "value2" is equal to 25, so the second part  of the "and" expression is true. But because one of the relational expressions were not true, "test1" is assigned a value of 0.  
 

   test2 = value1 > 5 and value2 = 12.5 * 2

Because variable "value1" is larger than 5, the first relational expression is true. Variable "value2" is equal to 12.5 * 2, so the second relational expression of the "and" logical expression is true. Because both expressions are true, "test2" is assigned a value of 1.

   test3 = value1 != 100 or value2 > 2000
 
The first relational expression of this "or" logical expression works out to be true because 50 is not equal to 100. The second relational expression works out to be false because 25 is not larger than 2000. As a result, the "or" logical expression works out to be true because at least one of the expressions was true, so variable "test3" is assigned a value of 1.
 
   test4 = value1 = 5 or value2 < 49
 
Variable "value1" is certainly not equal to 5, so the first relational expression is false. Variable "value2" is not smaller than 49, so the second relational expression is also false. Because neither relational expression worked out to a true value, the "or" logical expression is false. This means "test4" is assigned a value of 0.

Euphoria also has a "not" logical operator that gives you the opposite value of a relational expression. Here's a program example that best demonstrates this:
 
   atom opposite, result
   result = 15 < 20
   opposite = not result
 
First, "15 < 20" is evaluated, which has 1 (true) stored in variable "result", Next, "not" reverses the value in "result" to 0 (false), so the variable "opposite" is assigned a value of 0. In short, if the expression beside a "not" works out to be false, "not" reverses it to true. If the expression works out to be true, "not" reverses it to false."not" gives you the opposite value of the outcome of an expression. You can link as many relational and logical expressions together to make
larger complex expressions. You can even link arithmetic, relational and logical expressions together to formulate a value to be stored in the appropriate variable. However, you should know a few important things. In a situation where you are using the equal sign (=) in a relational expression, Euphoria uses a rule to define when the equal sign is an assignment operator and when it is a relational operator. The leftmost equal sign on the line is assumed to be an assignment operator. All other equal signs that follow are assumed to be relational operators. The outcome of arithmetic expressions can be tested with logical operators. This means you can do expressions like the following:

   complex_result = value1 * 5 and value2 - 8
 
If arithmetic expressions are used with logical operators, non-zero results like 5.2 or -4 are assumed true. Zero results still mean false. Euphoria also uses a system called precedence that defines which parts of larger complex expressions are done first by default. For example: 
 
   atom rent1, rent2, rent3, average_rent
   rent1 = 500
   rent2 = 600
   rent3 = 400
   average_rent = rent1 + rent2 + rent3 / 3
This example is supposed to work out the average of three rents. But precedence dictates that division is done first before addition. This means this program will work out the average of the rents incorrectly! We can fix this by using parentheses to force different parts of the expression to be worked out in a manner different from precedence of operators:
 
   average_rent = (rent1 + rent2 + rent3) / 3
 
This forces the three rents to be added together before division takes place. A complete list of precedence operators is in the Euphoria Reference Manual.
This completes your introduction to assigning atom (and object) type variables. If you clearly understand variable assignment, arithmetic, logical and relational expressions, and precedence, move on to sequence variable assignment in the next chapter. If not, please go over the two chapters again . You must understand these concepts before moving on to sequence variable assignment.

ToC
 
Assigning Values To Sequence Variables

Assigning values to sequence variables is just like assigning values to atom variables. Sequence variables can be given an actual value, or the result of an expression. And as with atom variables, the expressions can be arithmetic, relational or logical. However, because sequences consist of linked data objects instead of a single one, there are a few twists to learn about. It's important to note that the examples used in this chapter can also be applied to object type variables.  Here's a simple example of a sequence variable being assigned a value:
 
   sequence list_of_values
   list_of_values = {1,2,3,4,5,6,7,8,9,0}

It is also legal to assign a sequence variable the following value:
 
   sequence Mister_No_Elements
   Mister_No_Elements = {}

This is an example of a sequence value with no elements. You would use this approach to assign a sequence variable an "empty" value before using it in the program. It's similiar to setting an atom variable with a zero value. If you wanted to store a sequence value that was a person's name, address or city of residence, you could use the previously mentioned character string method to represent a sequence value.

   sequence my_name
   my_name = "David Alan Gay"

In this program example, we're storing "David Alan Gay" into a sequence variable meant to be my name. But understand that Euphoria converts this character string into the actual sequence value before it is stored in variable "my_name". If you could look inside variable "my_name", this is what you would see:
 
   {68,97,118,105,100,32,65,108,97,110,32,71,97,121}

It's important to note that a character string of "D" for example is NOT the same as 'D'. The former is a character string representation of a sequence value that is one element long, while the latter is a character representation of an atom value. Having said this, you shouldn't assume also that you can assign a one element long sequence value into both an atom variable and a sequence variable. An atom value and a one element long sequence value are NOT identical! The previous sequence variable assignment examples used values that are considered one-dimensional (where the elements are all atom values). Remember that sequences can also be composed of smaller sequences or a mix of atoms and smaller sequences. This program example assigns more complex sequence values to a series of sequence variables:
 
   sequence seq1, seq2
   seq1 = {{1,2,3}, {4,5,6}, {7,8,9}}
   seq2 = {{5,5,5,5,5,5,5}, -98, {100,-50,20.3}}

You could also represent the previous program example to help clarify the individual elements of each sequence using split lines:
 
   sequence seq1, seq2
   seq1 = {{1,2,3},
           {4,5,6},
           {7,8,9}}
   seq2 = {{5,5,5,5,5,5,5},
           -98,
           {100,-50,20.3}}

Instead of using constant elements in a sequence value, you are also allowed to use variable names and expressions to define the elements in a sequence value to be stored in a sequence variable: 
 
   sequence mixed_bunch
   atom some_atom_element
   some_atom_element = 502
   mixed_bunch = {"Euphoria", some_atom_element, some_atom_element/2}

Before this sequence value is stored in variable "mixed_bunch", each individual element must be worked out. In element 1, the character string "Euphoria" is converted to a true sequence value. In element 2, the value of "some_atom_element" is used. In element 3, the expression of the value of "some_atom_element" being divided by 2 is worked out. Once these steps are completed, the actual value is stored in "mixed_bunch". You can also use arithmetic, relational, and logical expressions to assign values to sequence variables, using the same operators introduced in the previous chapters on atom variable value assignment. This program example below works out a rent increase for five different apartments: 
 
   sequence old_rents, new_rents
   atom rent_increase
   old_rents = {413,500,435,619,372}
   rent_increase = 1.05
   new_rents = old_rents * rent_increase

Variable "old_rents" is given a 5-element sequence value that is the old rent amounts for five apartments. "rent_increase" is assigned the percentage to raise the rents by. "new_rents" is the new rents of the five apartments. Let's look at the statement that works out the new rents more closely:
 
   new_rents = old_rents * rent_increase

When using both atom and sequence variables or values in a binary expression (something that is made up of two parts), the atom part is replaced with a temporary sequence value that is as long as the other sequence. This is done before the expression is evaluated. As a result, variable "rent_increase"'s value becomes {1.05,1.05,1.05,1.05,1.05}. So, the above expression is then worked out in the following manner:
 
   element 1 of "old_rents" (413) × element 1 of temporary sequence (1.05)
   element 2 of "old_rents" (500) × element 2 of temporary sequence (1.05)
   element 3 of "old_rents" (435) × element 3 of temporary sequence (1.05)
   element 4 of "old_rents" (619) × element 4 of temporary sequence (1.05)
   element 5 of "old_rents" (372) × element 5 of temporary sequence (1.05)

The result of this element by element multiplication stores the value of:
 
   {433.65, 525, 456.75, 649.95, 390}
 
in variable "new_rents". This also works for logical and relational expressions as well. Here is a program example that uses sequence and atom in both expression types:
 
   sequence test1,test2
   test1 = {1,0,0} and 0
   test2 = {20,30,40} <= 30

Try to determine the value of "test1" and "test2" before going on to the next page. It's just like the rent increase program example!

   element 1 of {1,0,0} (1) and element 1 of {0,0,0} (0) = 0
   element 2 of {1,0,0} (0) and element 2 of {0,0,0} (0) = 0
   element 3 of {1,0,0} (0) and element 3 of {0,0,0} (0) = 0
   Thus, variable "test1" is assigned a value of {0,0,0}

   element 1 of {20,30,40} (20)  ≤  element 1 of {30,30,30} (30), giving a value of 1.

   element 2 of {20,30,40} (30)  ≤  element 2 of {30,30,30} (30), giving a value of 1.

   element 3 of {20,30,40} (40)  ≥  element 3 of {30,30,30} (30), giving a value of 0.

   Thus, variable "test2" is assigned a value of {1,1,0}

If two sequence variables or values are involved in a binary expression, both sequence lengths must be the same. For example, you cannot have an expression that tries to add a five element sequence and a six element sequence together to produce a result. You can, however, use sequences that are the same length but with different element types. This means you can add a sequence composed of atoms to a sequence composed of sequences. This program example helps clarify this point:
 
   sequence seq1, seq2
   seq1 = {1,0,1,0,1} or {0,1,0,1,0}
   seq2 = {2,{2,2},2} + {{2,2},2,{2,2}}

Variable "seq1" is assigned a value of {1,1,1,1,1}, while "seq2" is assigned a value of {{4,4},{4,4},{4,4}}. The rule of atoms and sequences in a binary expression was used in working out "seq2"'s value. This chapter not only taught you how to assign values to sequence type variables, it also showed you how powerful sequences can be in data manipulation. With a single Euphoria statement, you can change a series of linked values in a flash. Try doing that with a handful of atom variables! But all of this is at the top level of the sequence. How do we access and change individual elements of a sequence, or create new sequence values by joining existing atom and sequence values in our programs? Well, the next chapter will focus on these topics as we journey further in the adventure that is the Euphoria language!

ToC

Sequence Element Access And Manipulation
 
Even though we devoted an entire chapter of this tutorial to the assignment of sequence variables with entire sequence values, it is actually the handling of elements that will take up most of your time when programming with sequences. This makes sense, as sequences allow the programmer to handle many individual data objects very quickly and all at once. This chapter will show you how to extract elements out of sequences and also to link them together to make new sequences. To start off, you need to know the Euphoria syntax required to reference individual elements of a sequence. It is shown on the next page, as it requires a considerable amount of explanation.

   variable  =  sequence variable[element number(s)]

Accessing an element involves the use of an assignment statement. sequence variable contains the value that we want to reference the  elements in element number(s) means one or more element numbers that are being referenced. The square braces [ and ] are used to tell Euphoria that this is an element number and are always on either side of the number. The first element number in a sequence always starts at 1, and increases by one with the second and following elements after. Accessed elements of a sequence are stored in a receiving variable, defined here to the left of the equal sign as variable. The actual type of the variable to receive the element depends on the type of data object the element is. If the element is a sequence, the receiving variable must be able to hold sequences. If the element is an atom, the receiving variable must be able to hold atoms.
 
   sequence list_of_days, list_of_months, month_name
   atom days_in_month
   list_of_months = {"January","February","March","April","May","June",
                     "July","August","September","October","November","December"}
   list_of_days = {31,28,31,30,31,30,31,31,30,31,30,31}
   days_in_month = list_of_days[3]
   month_name = list_of_months[3]

This program example obtains the name and number of days for the month March from two sequence variables ("list_of_months" and "list_of_days") that were previously assigned data. "month_name" is given the value of the third element of "list_of_months", and "days_of_month" is given the third element of list_of_days". Notice both receiving variables have the correct variable type needed to accept the values. This is important! When accessing an element of a sequence that is itself a sequence, it is possible to access the elements inside that sequence as well. What is required is another element index to access a second level. To access elements within a two-dimensional index, you use the syntax below:
 
   variable  =  sequence variable [element number(s)][element number(s)]

If we were dealing with sequence made up of sequences, the first element number(s) serves as the index number needed to access any of the sequences making up the main sequence. The second element number(s) serves to access the elements within the sequence referenced by the first element number(s). A program example on the next page will help clear up any confusion in understanding how to use two indexes to reference elements.

   sequence days_of_months
   atom no_leap_february, leap_february
   days_of_months = {31,{28,29},31,30,31,30,31,31,30,31,30,31}
   no_leap_february = days_of_months[2][1]
   leap_february = days_of_months[2][2]

This program example extracts the number of days in February in both a leap year and non-leap year situation. Look at the second element of the sequence value stored in variable "days_of_months". It is itself a sequence two elements long. The atom variable "no_leap_february" is assigned the value of 28, the first element that makes up the sequence that is the second element of "days_of_months" ([2][1]), while atom variable "leap_february" is assigned 29, the second element that makes up the second element of "days_of_months" ([2][2]). Notice the indexes are in order of descending level, giving it a reversed appearance.

Here are the "dos" and "don'ts" of using element indexing in any sequence. First of all, you can replace a constant number with a variable name,  like "[element_id]" for example. You can also have more than two levels of element access if the sequence is built for it. However, if an element is an atom, you cannot use another level of element indexing to go deeper into that element: only elements that are sequences can be accessed in this manner. Also, you cannot use an element number of zero, or an element number that is larger than the length of the sequence (for example, trying to access element 4 in a sequence that is only 3 elements long). It's possible to reference more than one element of a sequence at a time. The syntax below is a variation of what you were introduced to before:
 
   seq. variable  =  seq. variable[starting element..ending element]

Euphoria uses double periods (..) to indicate that this is not a single element we are accessing but an inclusive (meaning including the starting and ending points) range of elements. The program example below shows how to access a range of elements:
 
   sequence nine_numbers, first_four, last_five
   nine_numbers = {1,2,3,4,5,6,7,8,9}
   first_four = nine_numbers[1..4]
   last_five = nine_numbers[5..9]
 
"first_four" contains {1,2,3,4} "last_five" contains {5,6,7,8,9}. A receiving variable is always of type sequence, as using a range returns a sequence value, even if the starting and ending elements are the same.  Accessing ranges follow the same rules as accessing individual elements. In addition, the starting and ending element numbers must be within the length of the accessed sequence. If the starting element number is equal to the ending element number + 1, a null sequence ({}) is returned. You cannot, however, have a situation where the starting element number is greater than the ending element number by more than 1. You can use ranges when dealing with multi-dimensional sequences, but there are some limitations as listed below in this example: 
 
   sequence bigseq, seq1, seq2
   bigseq = {{1,1,1},{2,2,2},{3,3,3}}
   seq1 = bigseq[1][1..2]
   seq2 = bigseq[1..2][1]
 
While you can access a range in a sequence element, you cannot reverse it to access an element out of a range of sequence elements, as in "seq2". If we changed the syntax around to place the referenced sequence element on the left side of the equal sign, we would have the ability to change the value of a specific element:
 
   sequence variable [element number(s)] = expression 
Here is a program example that demonstrates how to change both a single element and a range of elements:
 
   sequence bunch
   bunch = {"cat",5,{1,9,8,4},{0,0,0}}
   bunch[1][1] = 'b'
   bunch[2] = {7,7,7} + 1
   bunch[3][3..4] = {9,7}
   bunch[4][1..3] = -20

Let's walk through the program example to understand what is going on:
 
bunch = {"cat",5,{1,9,8,4},{0,0,0}}
 - assign variable "bunch" with  the value of {{99,97,116},5,{1,9,8,4},{0,0,0}}

bunch[1][1] = 'b'
 - access first element in element 1 of "bunch" and change it from 99 ('c') to
   (98) ('b'), "bunch[1]" is now {98,97,116}

bunch[2] = {7,7,7} + 1
 - access second element of "bunch" and change it to the value of
   expression {7,7,7} + 1, "bunch[2]" is now {8,8,8}

bunch[3][3..4] = {9,7}
 - access third and fourth elements in element 3 of "bunch", and replace with {9,7},
   "bunch[3]" is now {1,9,9,7}

bunch[4][1..3] = -20
 - access all three elements in element 4 of "bunch" and replace with {-20,-20,-20},
   "bunch[4]" is now {-20,-20,-20}

When a single atom value is being assigned to a range of elements, Euphoria converts this to a temporary sequence value equal to the length needed to cover the starting and ending element numbers in the range. The sequence value is made up of the original atom value repeated as many times as needed. That is why "bunch[4]" is assigned a value of {-20,-20,-20}. When the program example completes, the value of variable "bunch" is:
 
   {{98,97,116},{8,8,8},{1,9,9,7},{-20,-20,-20}}
 
You can also create new sequence values in variables by adding together existing atom or even sequences. To do this, you use the syntax below:
 
   sequence variable = expression & expression

The & operator joins together expressions that evaluate into atom or sequence values to form new sequences. The result is a sequence that is as long as (in elements) the total sum of the lengths of the atoms and sequences used in the joining. For example, joining a four element long sequence with an atom gives a five element long sequence. This program example demonstates the results of several joining attempts:
 
   sequence s1, s2, s3
   s1 = 5 & 4                              -- s1 is assigned {5,4}
   s2 = 90 & {30,60}                       -- s2 is assigned {90,30,60}
   s3 = {{1,1},{2,2,2}} & {3,3,3} + 1      -- s3 is assigned {{1,1},{2,2,2},4,4,4}

Congratulations! You now understand the basic concepts of Euphoria! Feel free to review the previous chapters again. A full understanding of the core concepts is needed to learn the topics in the next chapters ahead.

ToC