307 lines
12 KiB
Plaintext
307 lines
12 KiB
Plaintext
@database beginner.guide
|
|
|
|
@Master beginner
|
|
|
|
@Width 75
|
|
|
|
|
|
This is the AmigaGuide® file beginner.guide, produced by Makeinfo-1.55 from
|
|
the input file beginner.
|
|
|
|
|
|
@NODE "main" "Procedures and Functions"
|
|
@Next "Constants.guide/main"
|
|
@Prev "Format.guide/main"
|
|
@Toc "Contents.guide/main"
|
|
|
|
Procedures and Functions
|
|
************************
|
|
|
|
A @{fg shine }function@{fg text } is a procedure which returns a value. This value can be
|
|
formed from any expression so it may depend on the parameters with which
|
|
the function was called. For instance, the addition operator @{b }+@{ub } can be
|
|
thought of as a function which returns the sum of its two parameters.
|
|
|
|
|
|
@{" Functions " Link "Functions" }
|
|
@{" One-Line Functions " Link "One-Line Functions" }
|
|
@{" Default Arguments " Link "Default Arguments" }
|
|
@{" Multiple Return Values " Link "Multiple Return Values" }
|
|
|
|
|
|
@ENDNODE
|
|
|
|
@NODE "Functions" "Functions"
|
|
@Next "One-Line Functions"
|
|
@Toc "main"
|
|
|
|
Functions
|
|
=========
|
|
|
|
We can define our own addition function, @{b }add@{ub }, in a very similar way to
|
|
the definition of a procedure.
|
|
|
|
PROC main()
|
|
DEF sum
|
|
sum:=12+79
|
|
WriteF('Using +, sum is \\d\\n', sum)
|
|
sum:=add(12,79)
|
|
WriteF('Using add, sum is \\d\\n', sum)
|
|
ENDPROC
|
|
|
|
PROC add(x, y)
|
|
DEF s
|
|
s:=x+y
|
|
ENDPROC s
|
|
|
|
This should generate the following output:
|
|
|
|
Using +, sum is 91
|
|
Using add, sum is 91
|
|
|
|
In the procedure @{b }add@{ub } the value @{b }s@{ub } is returned using the @{b }ENDPROC@{ub } label. The
|
|
value returned from @{b }add@{ub } can be used in expressions, just like any other
|
|
value. You do this by writing the procedure call where you want the value
|
|
to be. In the above example we wanted the value to be assigned to @{b }sum@{ub } so
|
|
we wrote the call to @{b }add@{ub } on the right-hand side of the assignment. Notice
|
|
the similarities between the uses of @{b }+@{ub } and @{b }add@{ub }. In general, @{b }add(a,b)@{ub } can
|
|
be used in exactly the same places that @{b }a+b@{ub } can (more precisely, it can be
|
|
used anywhere @{b }(a+b)@{ub } can be used).
|
|
|
|
The @{b }RETURN@{ub } keyword can also be used to return values from a procedure.
|
|
If the @{b }ENDPROC@{ub } method is used then the value is returned when the
|
|
procedure reaches the end of its code. However, if the @{b }RETURN@{ub } method is
|
|
used the value is returned immediately at that point and no more of the
|
|
procedure's code is executed. Here's the same example using @{b }RETURN@{ub }:
|
|
|
|
PROC add(x, y)
|
|
DEF s
|
|
s:=x+y
|
|
RETURN s
|
|
ENDPROC
|
|
|
|
The only difference is that you can write @{b }RETURN@{ub } anywhere in the code part
|
|
of a procedure and it finishes the execution of the procedure at that
|
|
point (rather than execution finishing when it reaches the end of the
|
|
code). In fact, you can use @{b }RETURN@{ub } in the @{b }main@{ub } procedure to prematurely
|
|
finish the execution of a program.
|
|
|
|
Here's a slightly more complicated use of @{b }RETURN@{ub }:
|
|
|
|
PROC limitedadd(x,y)
|
|
IF x>10000
|
|
RETURN 10000
|
|
ELSEIF x<-10000
|
|
RETURN -10000
|
|
ELSE
|
|
RETURN x+y
|
|
ENDIF
|
|
/* The following code is redundant */
|
|
x:=1
|
|
IF x=1 THEN RETURN 9999 ELSE RETURN -9999
|
|
ENDPROC
|
|
|
|
This function checks to see if @{b }x@{ub } is greater than 10,000 or less than
|
|
-10,000, and if it is a limited value is returned (which is generally not
|
|
the correct sum!). If @{b }x@{ub } is between -10,000 and 10,000 the correct answer
|
|
is returned. The lines after the first @{b }IF@{ub } block will never get executed
|
|
because execution will have finished at one of the @{b }RETURN@{ub } lines. Those
|
|
lines are therefore just a waste of compiler time and can safely be
|
|
omitted (as the comment suggests).
|
|
|
|
If no value is given with the @{b }ENDPROC@{ub } or @{b }RETURN@{ub } keyword then zero is
|
|
returned. Therefore, all procedures are actually functions (and the terms
|
|
@{fg shine }procedure@{fg text } and @{fg shine }function@{fg text } will tend to be used interchangeably). So, what
|
|
happens to the value when you write a procedure call on a line by itself,
|
|
not in an expression? Well, as we will see, the value is simply discarded
|
|
(see @{"Turning an Expression into a Statement" Link "MoreExpressions.guide/Turning an Expression into a Statement" }). This is what happened in
|
|
the previous examples when we called the procedures @{b }fred@{ub } and @{b }WriteF@{ub }.
|
|
|
|
|
|
@ENDNODE
|
|
|
|
@NODE "One-Line Functions" "One-Line Functions"
|
|
@Next "Default Arguments"
|
|
@Prev "Functions"
|
|
@Toc "main"
|
|
|
|
One-Line Functions
|
|
==================
|
|
|
|
Just as the @{b }IF@{ub } block and @{b }FOR@{ub } loop have horizontal, single line forms,
|
|
so does a procedure definition. The general form is:
|
|
|
|
PROC @{fg shine }name@{fg text } (@{fg shine }arg1@{fg text }, @{fg shine }arg2@{fg text }, ...) IS @{fg shine }expression@{fg text }
|
|
|
|
Alternatively, the @{b }RETURN@{ub } keyword can be used:
|
|
|
|
PROC @{fg shine }name@{fg text } (@{fg shine }arg1@{fg text }, @{fg shine }arg2@{fg text }, ...) RETURN @{fg shine }expression@{fg text }
|
|
|
|
At first sight this might seem pretty unusable, but it is useful for very
|
|
simple functions and our @{b }add@{ub } function in the previous section is a good
|
|
example. If you look closely at the original definition you'll see that
|
|
the local variable @{b }s@{ub } wasn't really needed. Here's the one-line definition
|
|
of @{b }add@{ub }:
|
|
|
|
PROC add(x,y) IS x+y
|
|
|
|
|
|
@ENDNODE
|
|
|
|
@NODE "Default Arguments" "Default Arguments"
|
|
@Next "Multiple Return Values"
|
|
@Prev "One-Line Functions"
|
|
@Toc "main"
|
|
|
|
Default Arguments
|
|
=================
|
|
|
|
Sometimes a procedure (or function) will quite often be called with a
|
|
particular (constant) value for one of its parameters, and it might be
|
|
nice if you didn't have to fill this value in all the time. Luckily, E
|
|
allows you to define @{fg shine }default@{fg text } values for a procedure's parameters when
|
|
you define the procedure. You can then just leave out that parameter when
|
|
you call the procedure and it will default to the value you defined for it.
|
|
Here's a simple example:
|
|
|
|
PROC play(track=1)
|
|
WriteF('Starting to play track \\d\\n', track)
|
|
/* Rest of the code... */
|
|
ENDPROC
|
|
|
|
PROC main()
|
|
play(1) -> Start playing from track 1
|
|
play(6) -> Start playing from track 6
|
|
play() -> Start playing from track 1
|
|
ENDPROC
|
|
|
|
This is an outline of a program to control something like a CD player.
|
|
The @{b }play@{ub } procedure has one parameter, @{b }track@{ub }, which represents the first
|
|
track that should be played. Often, though, you just tell the CD player
|
|
to play, and don't specify a particular track. In this case, play starts
|
|
from the first track. This is exactly what happens in the example above:
|
|
the @{b }track@{ub } parameter has a default value of 1 defined for it (the @{b }=1@{ub } in the
|
|
definition of the @{b }play@{ub } procedure), and the third call to @{b }play@{ub } in @{b }main@{ub } does
|
|
not specify a value for @{b }track@{ub }, so the default value is used.
|
|
|
|
There are two constraints on the use of default arguments:
|
|
|
|
1. Any number of the parameters of a procedure may have default values
|
|
defined for them, although they may only be the right-most parameters.
|
|
This means that for a three parameter procedure, the second parameter
|
|
can have a default value only if the last parameter does as well, and
|
|
the first can have one only if both the others do. This should not
|
|
be a big problem because you can always reorder the parameters in the
|
|
procedure definition (and in all the places it has been called!).
|
|
|
|
The following examples show legal definitions of procedures with
|
|
default arguments:
|
|
|
|
PROC fred(x, y, z) IS x+y+z -> No defaults
|
|
|
|
PROC fred(x, y, z=1) IS x+y+z -> z defaults to 1
|
|
|
|
PROC fred(x, y=23, z=1) IS x+y+z -> y and z have defaults
|
|
|
|
PROC fred(x=9, y=23, z=1) IS x+y+z -> All have defaults
|
|
|
|
On the other hand, these definitions are all illegal:
|
|
|
|
PROC fred(x, y=23, z) IS x+y+z -> Illegal: no z default
|
|
|
|
PROC fred(x=9, y, z=1) IS x+y+z -> Illegal: no y default
|
|
|
|
2. When you call a procedure which has default arguments you can only
|
|
leave out the right-most parameters. This means that for a three
|
|
parameter procedure with all three parameters having default values,
|
|
you can leave out the second parameter in a call to this procedure
|
|
only if you also leave out the third parameter. The first parameter
|
|
may be left out only if both the others are, too.
|
|
|
|
The following example shows which parameters are considered defaults:
|
|
|
|
PROC fred(x, y=23, z=1)
|
|
WriteF('x is \\d, y is \\d, z is \\d\\n', x, y, z)
|
|
ENDPROC
|
|
|
|
PROC main()
|
|
fred(2, 3, 4) -> No defaults used
|
|
fred(2, 3) -> z defaults to 1
|
|
fred(2) -> y and z default
|
|
fred() -> Illegal: x has no default
|
|
ENDPROC
|
|
|
|
In this example, you cannot leave out the @{b }y@{ub } parameter in a call to
|
|
@{b }fred@{ub } without leaving out the @{b }z@{ub } parameter as well. To make @{b }y@{ub } have its
|
|
default value and @{b }z@{ub } some value other than its default you need to
|
|
supply the @{b }y@{ub } value explicitly in the call:
|
|
|
|
fred(2, 23, 9) -> Need to supply 23 for y
|
|
|
|
These constraints are necessary in order to make procedure calls
|
|
unambiguous. Consider a three-parameter procedure with default values for
|
|
two of the parameters. If it is called with only two parameters then,
|
|
without these constraints, it would not be clear which two parameters had
|
|
been supplied and which had not. If, however, the procedure were defined
|
|
and called according to these constraints, then it must be the third
|
|
parameter that needs to be defaulted (and the two parameters with default
|
|
values must be the last two).
|
|
|
|
|
|
@ENDNODE
|
|
|
|
@NODE "Multiple Return Values" "Multiple Return Values"
|
|
@Prev "Default Arguments"
|
|
@Toc "main"
|
|
|
|
Multiple Return Values
|
|
======================
|
|
|
|
So far we've only seen functions which return only one value, since
|
|
this is something common to most programming languages. However, E allows
|
|
you to return up to three values from a function. To do this you list the
|
|
values separated by commas after the @{b }ENDPROC@{ub }, @{b }RETURN@{ub } or @{b }IS@{ub } keyword, where
|
|
you would normally have specified only one value. A good example is a
|
|
function which manipulates a screen coordinate, which is a pair of values:
|
|
the x- and y-coordinates.
|
|
|
|
PROC movediag(x, y) IS x+8, y+4
|
|
|
|
All this function does is add 8 to the x-coordinate and 4 to the
|
|
y-coordinate. To get to the return values other than the first one you
|
|
must use a multiple-assignment statement:
|
|
|
|
PROC main()
|
|
DEF a, b
|
|
a, b:=movediag(10, 3)
|
|
/* Now a should be 10+8, and b should be 3+4 */
|
|
WriteF('a is \\d, b is \\d\\n', a, b)
|
|
ENDPROC
|
|
|
|
@{b }a@{ub } is assigned the first return value and @{b }b@{ub } is assigned the second. You
|
|
don't need to use all the return values from a function, so the assignment
|
|
in the example above could have assigned only to @{b }a@{ub } (in which case it would
|
|
not be a multiple-assignment anymore). A multiple-assignment makes sense
|
|
only if the right-hand side is a function call, so don't expect things
|
|
like the following example to set @{b }b@{ub } properly:
|
|
|
|
a,b:=6+movediag(10,3) -> No obvious value for b
|
|
|
|
If you use a function with more than one return value in any other
|
|
expression (i.e., something which is not the right-hand side of an
|
|
assignment), then only the first return value is used. For this reason
|
|
the return values of a function have special names: the first return value
|
|
is called the @{fg shine }regular@{fg text } value of the function, and the other values are
|
|
the @{fg shine }optional@{fg text } values.
|
|
|
|
PROC main()
|
|
DEF a, b
|
|
/* The next two lines ignore the second return value */
|
|
a:=movediag(10, 3)
|
|
WriteF('x-coord of movediag(21, 4) is \\d\\n', movediag(21,4))
|
|
ENDPROC
|
|
|
|
|
|
@ENDNODE
|
|
|