In the last chapter you gave an input box a name, so a button could send its contents to your program. Names are one of the most important ideas in ioL. They let you go back to something you've already put on the screen and read it, change it, or add to it, instead of printing everything again.
When the console reads a tag like <box {Hello}>, it creates a box on the screen.
That box stays in the console after the tag has been read: it's a tag instance. The tag was the
instruction; the tag instance is the thing it made.
To work with a tag instance later, give it an instance name when you create it, by writing the name and a colon in front of the tag type:
<greeting:span {Hello}>
This creates a span containing Hello, and names it greeting. The name doesn't change how the span looks. It just gives you a way to refer to it.
Write a name where you'd write a value, and you get the value of that tag instance's primary field.
You've already done this with <putLn name>. Inside a tag like that, you can write the
name on its own; elsewhere, put it in angle brackets like a tag:
<greeting:span {Hello}>
<putLn greeting> <! sends "Hello" to your program !>
The greeting says: <greeting> <! displays "The greeting says: Hello" !>
To read one of its other fields, add a dot and the field name:
<heading:span size=24,pt {Welcome}>
<putLn heading.size> <! sends the span's text size !>
This is important: reading a name gives you a copy of its value at that moment. If the value changes later, the copy doesn't change with it:
<points:scalar 5> Your score: <points></n> <! displays "Your score: 5" !> <points 99> Your score: <points> <! displays "Your score: 99" underneath; the line above still says 5 !>
(A scalar tag, used here, is invisible. It just holds a value, much like a variable in Python.) So how do you show something that changes, like a score? You change the tag instance that displays it, which is what the next section is about.
To replace the contents of a tag instance's primary field, write the name followed by the new value, like a tag:
<greeting:span {Hello}>
<greeting {Goodbye}> <! the span on screen now says Goodbye !>
To change another field, use a dot:
<greeting.color {red}>
You may also see an = written after the name: <greeting={Goodbye}> or
<greeting.color={red}>. The = is optional and makes no difference; it's allowed simply
because it reads naturally. The same goes for a tag's primary field when it's created: <score:scalar=0>
is the same as <score:scalar 0>.
There's a catch. A tag instance only has the fields it was created with. Our span was created without a color field, so the line above fails, and the terminal shows:
ioL | invalid reference | Not defined in reference scope: greeting.color.
If you'll want to change a field later, include it when you create the tag. If you don't want to choose a value yet, give it the value null:
<greeting:span color=null {Hello}>
<greeting.color {red}> <! now this works !>
Setting a field back to null later returns it to its default appearance.
Why does ioL work this way? Tags like box have dozens of possible fields. If every box always had all of them, names like color or title would be taken, and you couldn't use them for tags of your own inside the box. Because a tag only has the fields you give it, those names stay free: a box created without a color field can contain a span named color, and card.color will find the span.
Here's a program that keeps a score and displays it. Rather than printing the whole screen again each time the score changes, it creates the display once, with a name, and then just changes it:
score = 0
print('''
<console.title {Scoreboard}>
<span size=14,pt {Score:}></n>
<scoreText:span size=48,pt bold=true color=null {0}></n>
<button {+1} onClick=<putLn {/up}>>
<button {-1} onClick=<putLn {/down}>>
<button {Reset} onClick=<putLn {/reset}>>
<button {Quit} onClick=<putLn {/quit}>>
''')
while True:
command = input()
if command == '/up':
score += 1
elif command == '/down':
score -= 1
elif command == '/reset':
score = 0
elif command == '/quit':
break
print('<scoreText ' + str(score) + '>')
if score < 0:
print('<scoreText.color {red}>')
else:
print('<scoreText.color null>')
Score:The score turns red when it drops below zero. That only works because scoreText was created
with color=null.
Tags can contain other tags, and so can their names. A name created inside another tag belongs to that tag. From outside, you reach it with a dot, like a field:
<card:box {
<heading:span bold=true {Ada Lovelace}></n>
<job:span {Mathematician}>
}>
<card.job {Mathematician and writer}>
Writing just job at the top level wouldn't work: there's no job there, only inside card. The part of your document where a name can be used without a dot is called its scope. The rules are:
Scope lets you reuse simple names like heading in different parts of your interface, without them clashing. A card for each of three people could each have its own heading and job. Within the same scope, though, give each tag instance a different name.
One tag instance exists before your program prints anything: the console itself. It's named console, and everything your program prints goes inside it. That's what the lines from the chapter on making things look good were doing:
<console.title {My Program}>
<console.backgroundColor {white}>
They change fields of the console tag instance, exactly like <card.job ...>
changes a field of card.
Because your output is inside the console, the top level of your output is the console's own
scope, and you can leave out the console. part: <title {My Program}> does the
same thing. Writing it out in full makes it clearer what's being changed, so the examples in this guide
mostly do.
Everything your program receives through the console comes, one way or another, from the user. And users type all sorts of things: by accident, out of curiosity, or occasionally on purpose to see what breaks. Every program that accepts input has to answer two questions about it.
Does it make sense? If your program asks for a number, the user may type a word. If it asks for a
name, they may type nothing at all. You've already seen one way to check: isdigit() in the guessing game.
You'll meet more as you go on. The rule is simple: check input before you rely on it, and decide what to do if
it's wrong.
Could it be mistaken for something else? If your program prints text the user typed, any <, { or } in it could be read as markup. If your program treats certain lines as commands, the user might type one. In both cases, something the user typed as data has been mistaken for instructions.
Mistaking data for instructions is one of the oldest mistakes in computing. In 1988, the Morris worm spread across the early Internet partly by sending a program more input than it had room for, overwriting its instructions. A decade later, programmers discovered SQL injection: if a program builds a database command by pasting in text the user typed, a cleverly typed "name" can become part of the command, and read or destroy whatever it likes. Mistakes like these are still found in new software every year. Whatever language or system you use, it's worth asking of every piece of input: what is this allowed to mean?
The user's text can cross between your program and the console in either direction, and each direction has its own way of keeping things clear:
def raw(text):
data = text.encode('utf-8')
return '[' + str(len(data)) + '{' + text + '}]'
print('''
Type anything (even </<> or </{>):</n>
<message:input>
<button {Show} onClick=<putLn message>, message.clear>
<button {Quit} onClick=<putLn {/quit}>></p>
You typed: <echo:span bold=true {}>
''')
while True:
line = input()
if line == '/quit':
break
print('<echo ' + raw(line) + '>')
Type anything (even < or {):Note that raw counts the length of the text in bytes, as raw data requires, by encoding it first.
<job {Engineer}> at the top level in your card program. What appears in
the terminal? Why?<a:span {Some <span color=null {inner}> text}>. The inner span has no name, and
a has no color field of its own. So what do you think <a.color {red}> will
do? Try it. Then find out what happens if a contains two inner spans with color fields, and
if a has a color field of its own.