INPUT /  OUTPUT /  LANGUAGE





Instance Names and Scope

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.


Tags and tag instances

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.

Choosing names

Reading a tag instance

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 !>

Reading gives you a copy

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.

Changing a tag instance

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>.

Fields must exist before you can change them

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.

Example: a scoreboard

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:
-2
+1 -1 Reset Quit

The score turns red when it drops below zero. That only works because scoreText was created with color=null.

Scope: names inside other tags

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.

The console

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.

Trusting the user's input

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:


Try it

  1. Change the scoreboard so the score turns green when it reaches 10.
  2. Make a card for three different people, each a box with its own name and job spans inside. Then change just the second person's job.
  3. Add a field to the scoreboard's scoreText so you can also make the score italic when it's negative.
  4. Try writing <job {Engineer}> at the top level in your card program. What appears in the terminal? Why?
  5. Create <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.