So far you've given fields values like {black}, true and 24,pt without thinking too hard about them. This chapter looks at the different kinds of value in ioL, how to write each one, and how they behave.
There are four kinds:
(There's also a fifth kind, the reference pointer, which you'll meet much later.)
Inside a tag, text goes in braces: {like this}. Everything between the braces is part of the text, including spaces. You can use escape sequences in it, and tags, as you saw in the chapter on tags and fields.
Remember that your program's output as a whole is also treated as text, as if it were wrapped in an invisible pair of braces. That's why you don't need braces around the plain text you print.
When you put several values in a field without commas, any blocks of text that end up next to each other are joined together into one:
<box {Hello, } {world}> <! the box contains one piece of text: "Hello, world" !>
Numbers are written the way you'd expect, with no braces:
7 3.14 -28 0.5
Numbers and text are different things, even if they look alike. 42 is a number you can do arithmetic with, while {42} is just two characters of text. This matters when a field expects a number, such as a width or a size.
Just like in character codes, you can write numbers in binary, octal or hexadecimal by starting them with b, o or x:
| Written as | Number system | Value |
|---|---|---|
| b1010 | binary | 10 |
| o52 | octal | 42 |
| x1F | hexadecimal | 31 |
| b10110101.1 | binary, with a fractional part | 181.5 |
This only changes how you write the number. Once ioL has read it, it's just a number, and if it's displayed it appears in ordinary decimal. You've already used hexadecimal for colours: x2E8B57 is simply a number that ioL understands as a colour.
Hexadecimal digits A–F must be UPPERCASE. Here's why: xFADE is a number, but xfade could just as easily be a name you've chosen for something. Because the hexadecimal digits are always uppercase, ioL can tell them apart: x followed by uppercase digits is a number, and x followed by lowercase letters is a name.
An s at the end of a number, followed by a whole number, shifts the point that many places (to the left if the number is negative). It works in any number system:
| Written as | Meaning | Value |
|---|---|---|
| 52s-2 | 52 with the point moved 2 places left | 0.52 |
| 1.5s3 | 1.5 with the point moved 3 places right | 1500 |
| b1011s4 | binary 1011, point moved 4 places right | b10110000 (176) |
ioL stores whole numbers in a fixed amount of memory, so there's a limit to how big they can be: from -2,147,483,648 to 2,147,483,647. A calculation whose result goes past either end doesn't cause an error. Instead, it overflows: the result wraps round to the other end of the range, and you get a completely wrong answer, with no warning at all:
<add 2147483647, 1> <! generates -2147483648, not 2147483648 !> <mul 50000, 50000> <! generates -1794967296, not 2500000000 !>
Numbers with a decimal point can be much bigger, but they're only stored to a limited number of digits, so very large or very precise results get rounded.
For the sizes, positions and scores in a typical interface, none of this matters. But if your numbers could get large, do the arithmetic in your program instead, where your programming language gives you more control.
Overflow is one of the oldest kinds of bug in computing, and it has caused serious failures ever since the early days of programming in the 1960s. A famous example is the first launch of the Ariane 5 rocket in 1996, which destroyed itself less than a minute after lift-off because a number in its guidance software became too large for the space it was stored in. Whenever you store a number, in any language, it's worth asking: how big could this get?
true and false are values in their own right, written without braces. Fields that switch something on or off, like bold or visible, take one of these.
When a field or tag needs a true-or-false answer but is given some other kind of value, ioL decides whether that value counts as true:
| Counts as true | Counts as false |
|---|---|
|
true any number other than zero any text that isn't empty, even {false} or {0} |
false 0 empty text, {} null |
You'll use this a lot once you start making decisions in your code, in the chapter on logic.
null means "no value". It isn't zero, and it isn't empty text: it's the absence of any value at all. If null is displayed, nothing appears.
You'll often give a field the value null to say "I'm not choosing anything for this yet",
for example backgroundColor=null. You'll see why that's useful in the chapter on instance
names.
inf means infinity. You'll usually only see it as the result of dividing by zero. There's no negative infinity in ioL: dividing a negative number by zero gives inf too.
invalid means "there's no sensible answer". It's what you get when something goes wrong: a name that doesn't exist, an impossible operation, or a value ioL couldn't make sense of. When invalid ends up on screen, it appears as a marker so you can see where the problem is, and the terminal usually shows an error message explaining why.
Each of these three special values (and true and false) can also be used to test whether something is exactly that value. You'll see how in the chapter on logic.
When a tag displays values, it shows them one after another with nothing in between:
<box 1,2,3> <! shows "123" !>
<box {Total: }, 42> <! shows "Total: 42" !>
<box x1F> <! shows "31" !>
<box {x1F}> <! shows "x1F", because this is text !>
If you want spaces or commas between them, you need to add them yourself. (There's a tag that does this for whole lists of values, called join, which you'll meet later.)
Some data isn't text at all. An image file, for example, is a long series of bytes that would make no sense if you tried to read it as characters, and it can contain any byte at all, including } or >. You can't put data like that in braces, because ioL would have no way to know where it ends.
Instead, you tell ioL in advance exactly how many bytes are coming:
[number of bytes{the data}]
ioL reads exactly that many bytes, whatever they are, then expects }]. Raw data is a value of
its own, like a number, so it goes in a field (<box [5{hello}]>). It can't go inside a
block of text in braces, where [ is just an ordinary character. Escape sequences and
comments don't work inside raw data: every byte is taken exactly as it is. In Python, you'd send the
contents of a file like this:
import sys
def print_raw(filename):
with open(filename, 'rb') as f:
data = f.read()
print('[' + str(len(data)) + '{', end='')
sys.stdout.buffer.write(data)
print('}]', end='')
The count is in bytes, not characters. That's the same thing for plain English text, but not for every character: é, for example, takes two bytes. You'll use raw data to display pictures and play sounds, in the chapter on images and media.
<box {b1010}> and <box b1010>?
Predict what each shows, then try it.width=xfade in a box. What appears in the terminal, and why?