2.1.1 ITEM: 1. type integer
The integer type is used in Eidos to represent integers – whole numbers, with no fractional component. Unlike in many languages, exponential notation may be used to specify integer literals (“literals” means values stated literally in the script, rather than derived through calculations).
The integer type is advantageous primarily because it is exact; it does not suffer from any sort of roundoff error. Exact comparison with integer constants is therefore safe; roundoff error will not lead to problems caused by 0.999999999 being deemed to be unequal to 1. However, integer is disadvantageous because it can only represent a limited range of values, and beyond that range, results will be unpredictable. Eidos uses 64 bits to store integer values, so that range is quite wide; to −9223372036854775806 to 9223372036854775807, to be exact. That is broad, but it is still enormously narrower than the range of numbers representable with float.
2.1.2 ITEM: 2. type float
The float type is used in Eidos to represent all non-integer numbers – fractions and real numbers. Exponential notation may be used to specify float literals; in particular; literals with a decimal point or a negative exponent are taken to be of type float.
Note that this rule means that some literals are represented using float even though they could also be represented using integer.
The float type is advantageous primarily because it can represent an enormously wide range of values. Eidos uses C++’s double type to represent its float values; the range of values allowed will depend upon your computer’s settings, but it will be vast. If that range is exceeded, or if numerical problems occur, type float can also represent values as infinity or as “Not A Number” (INF and NAN, respectively, in Eidos). The float type is thus more robust for operations that might produce such values. The disadvantage of float is that it is inexact; some values cannot be represented exactly (just as 1/3 in base 10 cannot be represented exactly, and must be written as 0.3333333...). Roundoff can thus cause comparison errors, overflow and underflow errors, and the accumulation of numerical error.
Several float constants are defined in Eidos; besides INF and NAN, PI is defined as π (3.14159...), and E is defined as e (2.71828...).
2.1.3 ITEM: 3. type logical
The logical type represents true and false values, such as those from comparisons. In many languages this type is called something like boolean or BOOL; Eidos follows R in using the name logical instead.
There are no logical literals in Eidos. However, there are defined constants that behave in essentially the same way as literals. In particular, T is defined as true, and F is defined as false. These are the only two values that the logical type can take. As in a great many other languages, these logical values have equivalent numerical values; F is 0, and T is 1 (and in fact any non-zero value is considered to be true if converted to logical type). Values of type integer or float may therefore be converted to logical, and vice-versa.
2.1.4 ITEM: 4. type string
The string type represents a string of characters – a word, a sentence, a paragraph, the complete works of Shakespeare. There is no formatting on a string – no font, no point size, no bold or italic. Instead, it is just a character stream. A string literal must be enclosed by either single or double quotation marks, ' or ". This choice simplifies writing Eidos strings that themselves contain quote characters, because you can delimit the string with the opposite kind of quote. For example, 'You say, "Ere thrice the sun done salutation to the dawn"' is a string that contains double quotes, whereas "Quoth the Raven, 'nevermore'.” is a string that contains single quotes. Apart from this consideration, it does not matter whether you use single or double quotes; the internal representation is the same. The suggested convention is to prefer double quotes, all else being equal, since they are more universally used in other programming languages.
A complication arises if one wishes to include both single and double quotation marks within a string; whichever delimiter you choose, one or the other quote character will terminate the string literal. In this case, the quotation mark must be “escaped” by preceding it with a backslash, \. The backslash can be used to “escape” various other characters; to include a newline in a string, for example, use \n, and to include a tab, use \t. Since the backslash has this special meaning, backslashes themselves must be escaped as \\. An alternative to dealing with escape sequences is to use the “here document” style of string literal; see the Eidos manual for details on this.
2.7.2 ITEM: 5. type NULL
The NULL type two primary uses: as a return value, and as a parameter.
As a return value, NULL is used to indicate that a function had nothing useful to return. Some functions always return NULL, such as print(); print() sends its output directly to the Eidos console. It has nothing useful to return, so it returns NULL. (That NULL value does not normally get printed out by Eidos because it is marked as an “invisible” return, a side topic not really worth getting into here; invisible returns work much as they do in R).
Some functions will return a useful value if they can, but will return NULL if they can’t. Often a NULL return is a result of passing NULL in as an argument; garbage in, garbage out, as they say. For example, the readFile() function will return NULL if an error occurs that prevents the file read operation from completing. The calling code could then detect that NULL return and act accordingly – it might try to read from a different path, print an error, or terminate execution with stop(), or it might just ignore the problem, if reading the file was optional anyway (such as an optional configuration file to modify the default behavior of a script).
The other use of NULL, as mentioned above, is as an argument to a function. Passing NULL is occasionally a way of signaling that you don’t want to supply a value for an argument, or that you want a default behavior from the function rather than telling it more specifically what to do.
NULL cannot be an element of a vector of some other type; it cannot be used to mark missing or unknown values, for example. Instead, NULL is its own type of vector in Eidos, always of zero length. (There is also no NA value in Eidos like the one in R, while we’re on the topic of marking missing values. Not having to worry about missing values makes Eidos substantially simpler and faster, and Eidos – unlike R – is not designed to be used for doing statistical analysis, so marking missing values is not expected to be important. Eidos does support NAN – Not A Number – values in float vectors, however, which could conceivably be used to mark missing values if necessary.)
The basic philosophy of how Eidos handles NULL values in expressions and computations is that NULL in such situations represents a non-fatal error or an unknown value. If using the NULL value in some meaningful way could lead to potentially misleading or incorrect results, Eidos will generate a fatal error. The idea is to give Eidos code an opportunity to detect a NULL, and thus to catch and handle the non-fatal error; but if the code does not handle the NULL, using the NULL in further operations will result in a fatal error before the functioning of the code is seriously compromised. NULL values are thus a sort of third rail; there’s a good reason they exist, but you have to be very careful around them. They are a bit like zero-valued pointers in C (NULL), C++ (nullptr), Objective-C (nil), and similar languages; they are widely used, but if you ever use one the wrong way it is an immediate and fatal error. For further details, please consult the Eidos manual.
2.8.1 ITEM: 6. type object
In addition to logical, integer, float, string, and NULL, there is one more type in Eidos left to discuss: object. A variable of type object is a vector that contains elements; it is a container, a bag of stuff. In this way, it is similar to Eidos’s other types; a float vector in Eidos contains floating-point elements, whereas an object vector contains object-elements (often just called “objects”; whether one is referring to a single object-element or a vector of type object is generally clear from context). An object vector can also embody behavior: it has operations that it can perform using the elements it contains, which all belong to a class that defines the available behaviors. The object type in Eidos is thus similar to objects in other languages such as Java, C++, or R – except much more limited. In Eidos you cannot define your own object classes; you work only with the predefined object classes supplied by SLiM or whatever other Context you might be using Eidos within. These predefined object classes generally define Context-dependent object-elements related to the task performed by the Context; in SLiM, the classes are things such as mutations, genomic elements, and mutation types (described in SLiM’s documentation). Eidos itself also supplies a few built-in object classes, notably Dictionary and Image.
The behaviors of objects in Eidos manifest in two ways: objects can have properties (also called instance variables or member variables, in other languages) that can be read from and written to, and they can have methods (also called member functions, in other languages). The behavior of an object vector in Eidos is determined by the class of element the object contains; an Eidos object will always contain only one class of element (just as a float cannot contain string-elements, for example).
Instances of particular object classes – particular kinds of objects – are obtained via built-in functions and/or global constants and variables. For example, in SLiM there is a global constant called sim that represents the simulated species as an instance of the Species class.