The terminology I'm presenting here deals with the symbols we will encounter as we deal with routines, function calls, statement blocks, actions, and other various areas of programming. For starters, these symbols:
These
These
Finally, these
Embedded routines are attached to properties within object (or class) definitions and as such only exist for that object (or instance of that class). They have no name of their own, but can be referred to (and called) by the name of the property to which they are attached.
Standalone routines are written outside of object (or class) definitions, thus they "stand alone," hence the name. They must have a name (or they could never be called).
[SneezeMessage; print "You sneeze loudly.^"; return true; ];Let's examine this in detail, like we did with BoringRoom. (I'll try not to be so long-winded this time.) First, we have the opening bracket: [. In Inform, this is considered a directive, just like Constant or Include. It tells the compiler to do something: begin a routine definition.
Next comes the name of the routine: SneezeMessage. Whenever we want to call
this routine, we write
Now we have the first statement in the routine. Statements are what I think of as "programming." (Sure, that word really encompasses the entire design process, but statements are the instructions that tell the computer what to do, and I learned that a program is "a series of instructions carried out by a computer." Sic the semantics police on me if you want.) Anyways, the statement is
print "You sneeze loudly.^";Ah, the glorious print statement. It had to be one of, if not the, first statement I learned in BASIC. print simply tells the computer to write some text to the screen. In this case, it's literal text: "You sneeze loudly." which will never change, but it could be text contained within a variable, in which case it will be whatever text happens to be contained in that variable at that time. Notice the circumflex at the end of the text. This will cause the computer to skip down to the next line before printing anything else. You'll find there are times when you need to do this in order to make your output more legible.
The next statement,
return true;tells the computer to stop executing code in this routine and to go back to the point where this routine was called. The routine also provides a single value that can be used by the code which called the routine. In this case, that value is the special constant true, which has the numeric value of 1.
Finally, a closing bracket marks the end of the routine: ]. Note that the entire routine definition is terminated by a semicolon, just like the individual statements contained within it.
Routines are usually used to take in some sort of input, process it, and return some value which results from the processing (output). Let's look at a simple mathematical example: cubes. (If you tried to forget as much math as you could once you got out of school, cubing a number is multiplying it by itself and then multiplying the result by the original number again. In other words, # times # times #.) Inform does not have an operator for raising a number to a power, so we must use multiplication. Here's the routine:
[Cube x; return x*x*x; ];Not much to look at, huh? There are a couple of interesing things here, though. First, there's the header:
[Cube x;This routine accepts one parameter. Within the routine, we will call this parameter x. x will hold the value that was passed in when the routine was called.
When you call a routine and pass one or more values, from the calling side you refer to those values as arguments. However, when you look at the routine itself, you refer to the passed-in values as parameters.In other words, when we look at
Now this part still messes with my mind when I see an Inform routine, because I've never dealt with a programming language that did this: The number of variables declared in the routine header do not necessarily mean that that routine takes that many parameters. You must list all the variables which will be used in your routine, whether they are passed in (parameters) or simply working storage for the routine. I'll bring this up in later examples, but I found (find) it so confusing that I felt it was worth mentioning up front.
There's another mathematical operator that's both handy and often necessary. First,
you need to know that when Inform deals with numbers, it deals with whole (integer)
numbers only. Inform does not handle fractions (decimals). That means that
You must be careful not to perform division or modulus when the denominator (the number you are dividing into the other number) is 0. This will cause an error when the game is run, not during compilation.
One thing that's very important to know is the order in which these operations are performed. Those who have done a little programming or who are math oriented will probably know this by heart, but others may not, so I will demonstrate. Actually, you can skip this section if you can get the correct answer to this expression:
((12 + 6 * 5) / (3 + 20 / 4 - 1) + 4 % 3) * -2If you answered -14, you probably understand operator precedence and can go on to "What do I do with the returned value?" If you answered something like 0, -.33333, or -10.33333, or you couldn't figure it out at all, you should read this section carefully.
Mathematicians have decided that certain mathematical functions should be performed before others. This is called precedence. Here are four levels:
First, look at the parts in parentheses, starting with the first inner group:
((12 + 6 * 5) / (3 + 20 / 4 - 1) + 4 % 3) * -2 ------------ (12 + 6 * 5)There is an addition and a multiplication. The multiplication comes first, so we evaluate
6 * 5and get 30. Now we have
(12 + 30)which becomes 42.
Now we work on the second set of inner parentheses:
(3 + 20 / 4 - 1)Here we have an addition, a division, and a subtraction. The division comes first, so we evaluate
20 / 4and get 5. Now we have
(3 + 5 - 1)We perform the addition and subtraction from left to right, so first we get
(8 - 1)and then we get
(7)So now our expression is
(42 / 7 + 4 % 3) * -2This is a division, an addition, and a modulus. The division and modulus come first.
42 / 7is 6, and
4 % 3is 1 (the remainder of 4 divided by 3), so we have
(6 + 1) * -2which becomes
7 * -2The negative sign is applied to the 2, so we consider the value -2 to be something complete, not some sort of subtraction. Now we multiply 7 by -2 and get -14. Got it? Good. There will be a quiz tomorrow.
x = 1; y = 4; z = Cube(y); print "The value of ", y, " cubed is ", z, ".^"; print "The value of x is still ", x, ".^";I snuck some fancy stuff in the print statement. We'll get to that shortly. Right now we're interested in the call to
Within the
Now
x*x*xresulting in 64. This value is made available to the return statement, which ends the routine and passes 64 back to the statement
z = Cube(y);This statement is now effectively
z = 64;so the value 64 is assigned to z. Change the
[Initialise x y z; location = BoringRoom; move butter to player; move chocolate to player; print "^^^^^^Oh man, this is too much already! What's with the ~Constant,~ ~Include,~ ~Initialise,~ and all that other stuff? I thought we were going to take it slow...!^"; x = 1; y = 4; z = Cube(y); print "The value of ", y, " cubed is ", z, ".^"; print "The value of x is still ", x, ".^"; ];and add the
The value of 4 cubed is 64. The value of x is still 1.after the "Oh man..." stuff. Notice that I have demonstrated that
Also, take a look at the assignment of z. y is being passed
as the argument to
[SomeFunction a qz parm3;and you called it like this
SomeFunction(qz, r, total_weight)then a would receive the value in qz (from the call), qz (inside the routine) would receive the value in r, and parm3 would receive the value in total_weight.
Finally, I want to make it clear that you can pass literals as well as variables, and you can mix and match the two at any time. The previous call to the routine above could have been
SomeFunction(3, x, 45)By the way, you can return
x = 1; print x;Compile and run. Do you see it? Right before "INFORM BEGINNER'S GUIDE" there should be a (non-highlighted) 1. Why is it not on a line by itself? Because we didn't tell printing to continue on a new line after x was printed. Remember the circumflex (^) mentioned earlier which meant "continue printing on a new line"? Well, we could have used it here, but that means printing a value and literal text together in one statement, and I'm not there yet. Inform does provide a special statement to do this, however, so let's use it now. Add this line after the two you just added:
new_line;Compile and run. Boom, there it is. All by its lonesome. Having shown you the new_line statement, I'll let you know that I'll probably never use it again in this guide or the game file. I personally always use the circumflex.
Now what happens when the variable you want to print contains text? You must understand that to Inform (and computers in general), everything is a number. If you assign a string of text (which I will from here on in simply call a string) to a variable and then simply say print <variable name>, you won't get your string, but rather a number. Here, don't take my word for it. Change the assignment to this:
x = "This is a string";Compile and run. See the number? Told you. In order to get the actual string printed, you have to tell Inform that that's what you want to do. You do this with a rule. A rule is actually a routine (which means you can create your own), and Inform provides several rules for you. You specify the rule's name in parentheses before the variable you want to print using that rule. Change the print statement to this:
print (string) x;Compile and run. Well lookee there! We got our string.
You'll probably use rules mostly in conjunction with objects. Remove the last
three lines from
print "You are holding ", (a) chocolate, ". (a)^"; print "You are holding ", (the) chocolate, ". (the)^"; print "You are holding ", (The) chocolate, ". (The)^"; print "You are holding ", (name) chocolate, ". (name)^";Compile and run. Don't worry about the warning stating that x is declared but not used. Hopefully you get the idea of what each rule does. Notice that the only difference between (the) and (The) is that (The) prints "the" with a capital t. You can even override the behavior of the (a) rule, printing "some," "a whole bunch of," or anything else you might need. Remember that this works only with (a), that is, the indefinite article. (the) always prints "the."
Now since I just did it in the preceding four lines, I suppose I should talk about mixing literal text and values in a single print statement. All you do is separate the parts (called terms in the DM) with commas.
| ||
BASIC programmers take note: the commas do not mean "print beginning at the next tab stop." They are simply separators. You can equate them with semicolons in a BASIC PRINT statement. Also, spaces will not be added around numerics, so be sure to leave a space at the end of the preceding string and put one at the beginning of the following string, if any. Also, if you're printing two numerics together, put a space between them. |
In the next part we'll talk about using comparisons and loops.
And yes, folks, it's really free. I'm too cheap to pay for this.