amiga-e/amigae33a/E_v3.3a/Docs/BeginnersGuide/Procedures.guide

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