MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame^] | 1 | LPC Basics |
| 2 | Written by Descartes of Borg |
| 3 | first edition: 23 april 1993 |
| 4 | second edition: 22 june 1993 |
| 5 | |
| 6 | CHAPTER 4: Functions |
| 7 | |
| 8 | 4.1 Review |
| 9 | By this point, you should be aware that LPC objects consist of functions |
| 10 | which manipulate variables. The functions manipulate variables when they |
| 11 | are executed, and they get executed through *calls* to those functions. |
| 12 | The order in which the functions are placed in a file does not matter. |
| 13 | Inside a function, the variables get manipulated. They are stored in |
| 14 | computer memory and used by the computer as 0's and 1's which |
| 15 | get translated to and from useable output and input through a device |
| 16 | called data typing. String data types tell the driver that the |
| 17 | data should appear to you and come from you in the form of alphanumeric |
| 18 | characters. Variables of type int are represented to you as whole |
| 19 | number values. Type status is represented to you as either 1 or 0. |
| 20 | And finally type void has no value to you or the machine, and is not |
| 21 | really used with variable data types. |
| 22 | |
| 23 | 4.2 What is a function? |
| 24 | Like math functions, LPC functions take input and return output. |
| 25 | Languages like Pascal distinguish between the concept of proceedure abd |
| 26 | the concept of function. LPC does not, however, it is useful to |
| 27 | understand this distinction. What Pascal calls a proceedure, LPC |
| 28 | calls a function of type void. In other words, a proceedure, or function |
| 29 | of type void returns no output. What Pascal calls a function differs |
| 30 | in that it does return output. In LPC, the most trivial, correct |
| 31 | function is: |
| 32 | |
| 33 | ----- |
| 34 | void do_nothing() { } |
| 35 | ----- |
| 36 | |
| 37 | This function accepts no input, performs no instructions, and returns no |
| 38 | value. |
| 39 | |
| 40 | There are three parts to every properly written LPC function: |
| 41 | 1) The declaration |
| 42 | 2) The definition |
| 43 | 3) The call |
| 44 | |
| 45 | Like with variables, functions must be declared. This will allow the |
| 46 | driver to know 1) what type of data the function is returning as output, |
| 47 | and 2) how many input(s) and of what type those input(s) are. The |
| 48 | more common word for input is parameters. |
| 49 | A function declaration therefore consists of: |
| 50 | type name(parameter1, parameter2, ..., parameterN); |
| 51 | The declaration of a function called drink_water() which accepts a string as |
| 52 | input and an int as output would thus look like this: |
| 53 | |
| 54 | ----- |
| 55 | int drink_water(string str); |
| 56 | ----- |
| 57 | |
| 58 | where str is the name of the input as it will be used inside the function. |
| 59 | |
| 60 | The function definition is the code which describes what the function actually |
| 61 | does with the input sent to it. |
| 62 | The call is any place in other functions which invokes the execution of the |
| 63 | function in question. For two functions write_vals() and add(), you thus |
| 64 | might have the following bit of code: |
| 65 | |
| 66 | ----- |
| 67 | /* First, function declarations. They usually appear at the beginning |
| 68 | of object code. |
| 69 | */ |
| 70 | void write_vals(); |
| 71 | int add(int x, int y); |
| 72 | |
| 73 | /* Next, the definition of the function write_vals(). We assume that |
| 74 | this function is going to be called from outside the object |
| 75 | */ |
| 76 | void write_vals() { |
| 77 | int x; |
| 78 | |
| 79 | /*N Now we assign x the value of the output of add() through a call */ |
| 80 | x = add(2, 2); |
| 81 | write(x+"\n"); |
| 82 | } |
| 83 | |
| 84 | /* Finally, the definition of add() */ |
| 85 | int add(int x, int y) { |
| 86 | return (x + y); |
| 87 | } |
| 88 | ----- |
| 89 | |
| 90 | Remember, it does not matter which function definition appears first in the |
| 91 | code. This is because functions are not executed consecutively. Instead, |
| 92 | functions are executed as called. The only requirement is that the |
| 93 | declaration of a function appear before its definition and before the |
| 94 | definition of any function which makes a call to it. |
| 95 | |
| 96 | 4.3 Efuns |
| 97 | Perhaps you have heard people refer to efuns. They are externally defined |
| 98 | functions. Namely, they are defined by the mud driver. If you have |
| 99 | played around at all with coding in LPC, you have probably found some |
| 100 | expressions you were told to use like this_player(), write(), say(), |
| 101 | this_object(), etc. look a lot like functions. That is because they are |
| 102 | efuns. The value of efuns is that they are much faster than LPC functions, |
| 103 | since they already exist in the binary form the computer understands. |
| 104 | |
| 105 | In the function write_vals() above, two functions calls were made. The first was to |
| 106 | the functions add(), which you declared and defined. The second call, however, |
| 107 | was to a function called write(), and efun. The driver has already declared |
| 108 | and defined this function for you. You needs only to make calls to it. |
| 109 | |
| 110 | Efuns are created to hanldle common, every day function calls, to handle |
| 111 | input/output to the internet sockets, and other matters difficult to be |
| 112 | dealt with in LPC. They are written in C in the game driver and compiled |
| 113 | along with the driver before the mud comes up, making them much faster |
| 114 | in execution. But for your purposes, efun calls are just like calls |
| 115 | made to your functions. Still, it is important to know two things of any |
| 116 | efun: 1) what return type does it have, and 2) what parameters of what |
| 117 | types does it take. |
| 118 | |
| 119 | Information on efuns such as input parameters and return types is often |
| 120 | found in a directory called /doc/efun on your mud. I cannot |
| 121 | detail efuns here, because efuns vary from driver to driver. However, |
| 122 | you can often access this information using the commands "man" or "help" |
| 123 | depending on your mudlib. For instance, the command "man write" would |
| 124 | give you information on the write efun. But if all else fails, |
| 125 | "more /doc/efun/write" should work. |
| 126 | |
| 127 | By looking it up, you will find write is declared as follows: |
| 128 | |
| 129 | ----- |
| 130 | void write(string); |
| 131 | ----- |
| 132 | |
| 133 | This tells you an appropriate call to write expects no return value and |
| 134 | passes a single parameter of type string. |
| 135 | |
| 136 | 4.4 Defining your own functions |
| 137 | Although ordering your functions within the file does not matter, ordering |
| 138 | the code which defines a function is most important. Once a function |
| 139 | has been called, function code is executed in the order it appears |
| 140 | in the function definition. In write_vals() above, the instruction: |
| 141 | |
| 142 | ----- |
| 143 | x = add(2, 2); |
| 144 | ----- |
| 145 | |
| 146 | Must come before the write() efun call if you want to see the appropriate |
| 147 | value of x used in write(). |
| 148 | |
| 149 | With respect to values returned by function, this is done through the "return" |
| 150 | instruction followed by a value of the same data type as the function. In |
| 151 | add() above, the instruction is "return (x+y);", where the value of (x+y) |
| 152 | is the value returned to write_vals() and assigned to x. On a more |
| 153 | general level, "return" halts the execution of a function and returns |
| 154 | code execution to the function which called that function. In addition, |
| 155 | it returns to the calling function the value of any expression that follows. |
| 156 | To stop the execution of a function of type void out of order, use |
| 157 | "return"; without any value following. Once again, remember, the data |
| 158 | type of the value of any expression returned using "return" MUST be the |
| 159 | same as the data type of the function itself. |
| 160 | |
| 161 | 4.5 Chapter Summary |
| 162 | The files which define LPC objects are made of of functions. Functions, in |
| 163 | turn, are made up of three parts: |
| 164 | 1) The declaration |
| 165 | 2) The definition |
| 166 | 3) The call |
| 167 | Function declarations generally appear at the top of the file before any |
| 168 | defintions, although the requirement is that the declaration must appear |
| 169 | before the function definition and before the definition of any function |
| 170 | which calls it. |
| 171 | Function definitions may appear in the file in any order so long as they |
| 172 | come after their declaration. In addition, you may not define one function |
| 173 | inside another function. |
| 174 | Function calls appear inside the definition of other functions where you |
| 175 | want the code to begin execution of your function. They may also appear |
| 176 | within the definition of the function itself, but this is not recommended |
| 177 | for new coders, as it can easily lead to infinite loops. |
| 178 | |
| 179 | The function definition consists of the following in this order: |
| 180 | 1) function return type |
| 181 | 2) function name |
| 182 | 3) opening ( followed by a parameter list and a closing ) |
| 183 | 4) an opening { instructing the driver that execution begins here |
| 184 | 5) declarations of any variables to be used only in that function |
| 185 | 6) instructions, expressions, and calls to other functions as needed |
| 186 | 7) a closing } stating that the function code ends here and, if no |
| 187 | "return" instruction has been given at this point (type void functions |
| 188 | only), execution returns to the calling function as if a r"return" |
| 189 | instruction was given |
| 190 | |
| 191 | The trivial function would thus be: |
| 192 | |
| 193 | ----- |
| 194 | void do_nothing() {} |
| 195 | ----- |
| 196 | |
| 197 | since this function does not accept any input, perform any instructions, or |
| 198 | return any output. |
| 199 | |
| 200 | Any function which is not of type void MUST return a value of a data type |
| 201 | matching the function's data type. |
| 202 | |
| 203 | Each driver has a set of functions already defined for you called efuns |
| 204 | These you need neither need to declare nor define since it has already |
| 205 | been done for you. Furthermore, execution of these functions is faster |
| 206 | than the execution of your functions since efuns are in the driver. |
| 207 | In addition, each mudlib has special functions like efuns in that they |
| 208 | are already defined and declared for you, but different in that they |
| 209 | are defined in the mudlib and in LPC. They are called simul_efuns, or |
| 210 | simulated efuns. You can find out all about each of these as they are |
| 211 | listed in the /doc/efun directory on most muds. In addition many |
| 212 | muds have a command called "man" or a "help" command which allows you |
| 213 | simply to call up the info files on them. |
| 214 | |
| 215 | Note on style: |
| 216 | Some drivers may not require you to declare your functions, and some |
| 217 | may not require you to specify the return type of the function in its |
| 218 | definition. Regardless of this fact, you should never omit this information |
| 219 | for the following reasons: |
| 220 | 1) It is easier for other people (and you at later dates) to read your |
| 221 | code and understand what is meant. This is particularly useful |
| 222 | for debugging, where a large portion of errors (outside of misplaced |
| 223 | parentheses and brackets) involve problems with data types (Ever |
| 224 | gotten "Bad arg 1 to foo() line 32"?). |
| 225 | 2) It is simply considered good coding form. |