PlatformDevelopment1.4.pdf

Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...

Full Transcript

i DAE.IGP Platform Development 1 2024-2025 Jef Daels ii Content Introduction ix Introducing programming...

i DAE.IGP Platform Development 1 2024-2025 Jef Daels ii Content Introduction ix Introducing programming xi 0.1 From bits to programs................................ xi 0.2 Simplied, incomplete evolution of programming.................. xiii 0.3 Platform Development 1: C# and MonoGame................... xvii C# comments and command delimiter xix 0.4 Introduction...................................... xix 0.5 C# comments: // or............................ xix 0.6 C# command delimiter: ;.............................. xx 1 Variables and datatypes 1 1.1 Introduction...................................... 3 1.2 C#: String datatype................................. 4 1.2.1 String example................................ 4 1.2.2 String values................................. 4 1.2.3 Special String values............................. 5 1.2.4 String expressions............................... 6 1.2.5 String values are immutable......................... 7 1.2.6 String variables................................ 7 1.2.7 Variable assignment.............................. 8 1.3 C#: int datatype................................... 9 1.3.1 int example.................................. 9 1.3.2 int values................................... 10 1.3.2.1 int literals.............................. 10 1.3.2.2 Special int value notations..................... 10 1.3.2.3 Special int values.......................... 11 1.3.2.4 Random int values......................... 11 1.3.3 int operations................................. 12 1.3.3.1 Binary int operators........................ 12 1.3.3.2 Unary int operators........................ 12 1.3.3.3 Operator precedence........................ 12 1.3.3.4 int datatype functionality..................... 13 1.3.4 int values are immutable........................... 13 iii iv CONTENT 1.3.5 int variables.................................. 13 1.3.5.1 Declaration, assignment, use.................... 13 1.3.5.2 Compound assignment....................... 14 1.3.5.3 Unary int operators: ++ and --.................. 14 1.4 C#: oat datatype.................................. 15 1.4.1 oat example................................. 15 1.4.2 oat values.................................. 15 1.4.2.1 oat literals............................. 15 1.4.2.2 oat value rounding errors..................... 16 1.4.2.3 Special oat value notations.................... 16 1.4.2.4 oat values. Special........................ 16 1.4.2.5 Random oat values........................ 16 1.4.3 oat operations................................ 16 1.4.3.1 Numeric oat operations...................... 16 1.4.3.2 Numeric operations which mix int and oat values....... 17 1.4.3.3 oat datatype functionality.................... 17 1.4.4 oat variables................................. 17 1.5 C#: double datatype................................. 18 1.5.1 double values................................. 18 1.6 C#: decimal datatype................................ 19 1.7 Rounding errors.................................... 19 1.8 C#: char datatype: self study............................ 20 1.9 Tuple data types................................... 20 1.9.1 Tuple..................................... 20 1.9.2 Tuple data types and variables........................ 21 1.9.2.1 var keyword............................. 21 1.9.3 Tuple eld names............................... 22 1.9.4 Deconstructing tuples............................. 23 1.10 Constants....................................... 23 1.11 Datatype transformations.............................. 25 1.11.1 Datatype transformation terminology.................... 25 1.11.2 Type casting................................. 25 1.11.2.1 Explicit type casting........................ 26 1.11.2.2 Implicit type casting........................ 26 1.11.3 Conversion................................... 27 1.12 Variable naming.................................... 28 1.13.NET framework................................... 28 1.14 Clean code....................................... 29 1.14.1 Concerning variable names.......................... 29 1.14.2 Concerning magic numbers.......................... 30 1.15 Chapter take aways.................................. 31 1.16 Technical references.................................. 31 1.17 Supportive videos................................... 31 CONTENT v 2 Methods 33 2.1 Methods introduction................................. 35 2.2 Method denition................................... 36 2.2.1 Method header................................ 36 2.2.1.1 Optional arguments........................ 37 2.2.2 Method body................................. 38 2.3 Calling a method................................... 38 2.3.1 How to call a method with positional arguments.............. 38 2.3.2 How to call a method with named arguments............... 39 2.4 C#: return keyword................................. 40 2.5 Nested arguments................................... 40 2.6 Calling mechanisms.................................. 40 2.7 Revisiting the method example........................... 42 2.8 Signature of a method................................ 43 2.9 Method overloading.................................. 43 2.10 Abstraction by parametrization........................... 45 2.11 keyword static..................................... 46 2.12 Local functions in C#7................................ 46 2.13 Method refactoring.................................. 46 2.14 Methods and tuples.................................. 46 2.14.1 Returning tuples............................... 46 2.14.2 Tuple eld names............................... 48 2.14.3 Method tuple formal arguments....................... 50 2.15 Clean code....................................... 50 2.16 Chapter datatype: DateTime............................ 51 2.17 Chapter take aways.................................. 52 3 Concerning variables 53 3.1 Instance and local variables............................. 53 3.2 Scope of a variable name............................... 54 3.2.1 Scope denition................................ 54 3.2.1.1 Variable shadowing......................... 54 3.2.2 Scope example................................ 55 3.3 Lifetime of a variable................................. 56 3.4 Default value of a variable.............................. 56 3.5 How to choose between instance and local variables?............... 57 3.6 C#: a static typed language............................. 58 3.7 Variables: terminology................................ 58 3.8 Clean code....................................... 58 3.9 Chapter datatype: Rectangle............................ 58 3.10 Chapter take aways.................................. 59 vi CONTENT 4 Selections 61 4.1 C#: Boolean datatype................................ 63 4.1.1 Boolean introduction............................. 63 4.1.2 Boolean values................................ 63 4.1.2.1 Boolean values: true and false................... 63 4.1.2.2 Generating Boolean values: comparison operators........ 63 4.1.2.3 Generating Boolean values: comparing Strings.......... 64 4.1.2.4 Boolean operators......................... 64 4.1.3 Boolean expressions.............................. 65 4.1.3.1 Ternary conditional operator ?:.................. 65 4.2 Selection introduction................................ 67 4.3 C#: if [else]...................................... 67 4.3.1 if [else]..................................... 67 4.3.1.1 Nested if else............................ 68 4.3.2 Nested selections: order is important.................... 69 4.4 C#: switch...................................... 70 4.5 C#: ?: operator.................................... 70 4.6 Not all code paths return a value.......................... 71 4.7 Concerning the return statement.......................... 71 4.8 Code block scope................................... 72 4.9 Some alternatives to 1 question........................... 73 4.9.1 IsVowel: 4 dierent solutions......................... 73 4.9.2 Are rectangles intersecting?......................... 73 4.10 TryParse........................................ 75 4.11 Recursion....................................... 75 4.11.1 Recursion example: factorial......................... 75 4.11.2 recursion example: programming repetition in a weird way........ 76 4.11.3 Recursion advantages............................. 77 4.12 Clean code....................................... 77 5 Iterations 79 5.1 C#: List datatype.................................. 81 5.2 Iterations introduction................................ 82 5.3 C#: while statement................................. 82 5.3.1 C#: while introduction example....................... 82 5.3.2 C#: while , practical example........................ 82 5.4 C#: do statement.................................. 84 5.4.1 C#: do , introduction example........................ 84 5.4.2 C#: do , practical example.......................... 84 5.5 C#: for statement.................................. 85 5.5.1 C#: for, introduction example........................ 85 5.5.2 C#: for, practical example.......................... 85 5.6 C#: foreach...................................... 86 5.7 C#: break , continue and yield keyword....................... 86 CONTENT vii 5.7.1 C#: break keyword.............................. 86 5.7.2 C#: continue keyword............................ 86 5.7.3 C#: yield keyword.............................. 86 5.8 Deleting specic elements in a list.......................... 87 5.9 Every while has a corresponding for and vice versa................ 88 6 Language INtegrated Query: LINQ 89 6.1 Enumerable.Range.................................. 91 6.2 Projection....................................... 92 6.3 MinBy and MaxBy.................................. 93 6.4 Sum.......................................... 93 6.5 Ordering........................................ 94 6.6 Filtering........................................ 95 6.7 Take.......................................... 95 6.8 LINQ: set operations................................. 95 6.9 LINQ method chaining................................ 95 6.10 LINQ......................................... 96 viii CONTENT Introduction This course intends to introduce the reader to programming. Many programming languages exist, all of them with specics which make them the right choice in certain situations, and a # sub optimal choice in others. This course introduces C , the programming language used in Unity. To keep the focus on programming we use the simpler MonoGame environment instead of Unity to develop our games with. Once you know C # , switching to programming in Unity is the natural next step. ix x INTRODUCTION Introducing programming 0.1 From bits to programs When executing (or running) a program, we expect this program to perform tasks, visualize reports, control a machine, register input, play games, play music,.... Although each of these tasks work with dierent kinds of data (text, images, audio, video,..), all the information found inside the computer consists of sequences of ones (1) and zeros (0). ˆ a bit is a unity of information which can contain either a zero (0) or a one (1); ˆ information consisting of bits is called binary data (binary because each element is one of two possibilities); ˆ in many situations, bits are combined in blocks of 8 bits, which are called byte s The process of a CPU (Central Processing Unit) at work is nicely illustrated in the video How a CPU Works (this is not exam stu ). At 3'40", we see the following image: Figure 1: Bits owing to the CPU ˆ at the right side, we see a lot of binary data, presented in 2 columns, organized in bytes; xi xii INTRODUCING PROGRAMMING  the left column identies dierent memory locations identied by binary numbers called addresses. These addresses increase one at a time: they are consecutive places in the memory of the device;  the right column shows the content (data) found at these addresses. What is not clearly visible from this image is the fact that, although the rightmost column values all look similar, they actually have a very distinct meaning which get's explained in the next image At 3'50", we see an image which interprets the information owing to the CPU in three very dierent ways:: Figure 2: Types of information owing to the CPU ˆ instructions: command's to be executed by the CPU (eg: the mov(e) instruction in the 8086 processor is 100010); ˆ addresses these instructions work with (eg: the address the instruction should move a value to); ˆ values these instructions work with (eg: the value which should be moved by the instruction); As the image shows, the dierent type of information elements (instructions, addresses and values) are placed intermixed one after the other, and are very hard for a human to interpret: don't try to make sense out of it, just understand the intention! The right side column makes up the program: a program consists of a sequence of instructions which perform a desired task. 0.2. SIMPLIFIED, INCOMPLETE EVOLUTION OF PROGRAMMING xiii ˆ instructions are commands known by the CPU;  these instructions manipulate data which can be a specic value or an address whose internal value should be used;  the set of all instructions known by a CPU is called its instruction set. ˆ dierent CPU architectures (X86-64, AMD,..) have dierent instruction sets, which make it impossible to use the same binary code on dierent CPU architectures;  within an architecture, we expect the instruction set to be backwards compatible. Remark: if you are interested in instruction set architectures ( ISA), you can nd some extra info in Wikipedia: Instruction set architecture. Rest assured: this reference is far outside the scope of this course. 0.2 Simplied, incomplete evolution of programming Programming is the process which results in a specic set of instructions and their corresponding values (addresses and constant values) which are fed to the CPU to perform a desired behavior. Through the years, programming evolved considerably: ˆ at rst, one had to manually write the binary codes for the instructions send to the CPU: machine code , written in a machine language. This is very error prone and hard to do.  Since the binary instructions are not portable between CPU architectures, the program must be hand written for every architecture this program should be available on.;  because evolutions of the same CPU architecture are backwards compatible, software which runs on the older version of the architecture will run on the newer version as well.  bit codes can be written in hexadecimal code : every four bits are combined into a hexadecimal number (4 bits allow for 14 combinations which can be written with hexadecimal numbers: 0,1,.. 9, A, B, C, D, E, F. ˆ very quickly, Wikipedia: Assembly languages (outside the scope of this course) were developed.  These languages replace the numerical code of an instruction with a mnemonic code: mov instead of 100010, which makes the code much more readable;  memory locations were identied using labels (names), which again reduces the number of errors and yields more readable code; Just like machine code, assembly (code) is specic to a certain architecture. So, if you want a certain program to be executable on dierent architectures, you still need to code the dierent versions for all architectures. xiv INTRODUCING PROGRAMMING  programming assembler instructions introduced the need for an assembler program, which translates these mnemonic codes into binary instructions. Remember, in the end, a CPU only processes these binary instructions, not assembler instructions. ˆ the next step introduced 'higher level' programming languages. FORTRAN and COBOL are notorious examples. These languages introduce some important abstractions:  variable names replace memory addresses (much like the labels in assembler). This way, you don't have to type memory address numbers anymore, but simply use the variable to refer to a specic location in memory.  datatype info is introduced. This datatype info denes the potential values which can be stored at, and operations which can be performed with the values found at a memory location with this datatype. (see Variables and datatypes for more details);  common programming elements (writing iterations, performing a logical test to choose what code to execute,..) are dened in the programming language to replace the entire CPU architecture specic instruction set * the main advantage of this is the fact that the programmer only needs to know the programming language instructions, not the instruction set of the CPU architecture the program will be executed on.  translating these programming language instructions into machine code instructions is done by a Wikipedia: compiler. Each CPU architecture needs a specic compiler to translate the same program code (written in COBOL, FORTRAN,..) to machine instructions specic to this architecture. The big advantage is the fact that the program you write in this programming language (without considering architecture specics) can now automatically be compiled for a specic architecture if a compiler of this programming language for this specic architecture exists. * if you develop a game in a programming language (say C #) for which we have a compiler for both Intel and AMD hardware, the game can be played on both hardware platforms after compiling for those platforms. ˆ through the years, a lot of new languages have been developed. A programming language with a long lasting eect is Wikipedia: C programming language. It's very portable (almost every CPU architecture comes with a C compiler), very ecient and has introduced a syntax which is used (in some form) in a lot of programming languages like C + +, Java, C # , javascript,... 0.2. SIMPLIFIED, INCOMPLETE EVOLUTION OF PROGRAMMING xv ˆ if you are interested in the current popularity of programming languages, one can check indices like Tiobe index : Figure 3: Tiobe index: programming language popularity ˆ scripting languages like JavaScript and Python compile the higher level programming language one line at a time while executing, while programming languages like C # and C++ compile the complete program before executing it; ˆ the usefulness of a programming language depends on its instruction set and (even more) on the available libraries. As an example, Python is very good at programming data projects because it comes with very good data analysis libraries;  a library is a program which contains functionality exposed to other programs. Eg, drawing nice statistical graphs is available in Python libraries, removing the need for you to program this yourself; ˆ some compilers compile a programming language to an other program language (like C), which then in turn is compiled to machine code (so a compiler not necessarily produces machine code. If it doesn't, an extra compilation to machine code is still needed to obtain something which can be executed);  C # is compiled to CIL (Common Intermediate Language) which then gets executed by the.NET platform which should be available on the CPU architecture. ˆ some programming languages (like Java) compile to the instruction set of a virtual machine. This is a virtual (not hardware) CPU architecture which is a program running xvi INTRODUCING PROGRAMMING on some real CPU. In this case, your program can be executed on every device which runs your virtual CPU (as a program); ˆ Wikipedia: WebAssembly is low level (assembler like) code which can be executed by most browsers. Since most platforms support these browsers, webassembly programs can be run on most devices. ˆ some programming languages ( SQL, ProLog ) don't code the instructions describing the program ow (how to compute something, the algorithm ), but simply specify the constraints of the solution. The latter is called declarative programming , the former is procedural programming. Some terminology: ˆ source code: the program code written by the developer; ˆ key words: the programming languages dene keywords which are words with a special meaning in this programming language. These keywords are dierent for each programming language (although they overlap). Since these keywords have a special meaning, the programmer should be aware of them, so that they are not used wrongly. As an example, nd below both C # and python keyword lists taken from C # keywords and Python Keywords: An Introduction Figure 4: C # keywords 0.3. PLATFORM DEVELOPMENT 1: C# AND MONOGAME xvii Figure 5: Python keywords ˆ operators (+, -, *,..) are similar to keywords but not words: they are sequences of characters with a specic meaning in this programming language. Eg: && indicates the conditional and # operator in C , which will be explained in the chapter concerning conditionals. 0.3 Platform Development 1: C# and MonoGame I hope the previous section convinced you that a lot of programming languages exist, each better # or worse suited for a specic problem setting. In this course, we will work with C because it's the programming language used in Unity, the game engine we will start using in the next courses. In this rst course, we will use MonoGame as our game engine because MonoGame is less complex and allows us to focus more on programming. ˆ the 3D environment in Unity makes it harder to get started with simple examples. Since # this course is all about C programming, we use a simpler game engine: MonoGame. The previous section described how programming languages are compiled into machine instructions for a CPU. Although this is a very important step, we consider the existence of # the C compiler as a given, and pay no more attention to it. Our programming reasoning will # be in the C programming language, not in the generated lower level code. xviii INTRODUCING PROGRAMMING C# comments and command delimiter 0.4 Introduction We will introduce C# in the Integrated Development Environment (IDE) Visual Studio (a program, like Word). If you are unfamiliar with Visual Studio, I strongly recommend reading the appendix Visual Studio introduction before the remainder of this chapter. Other good IDE's (alternatives for Visual Studio) exist, eg. Jetbrains Rider which is also free for students. Before we can start writing C # programming instructions, we should know how to add comments to a program (to increase readability) and how to code a command delimiter which is used to separate one command (instruction) from an other. 0.5 C# comments: // or ˆ //: single line comments: the // and everything after it on the same line are the comment, which will not generate machine instructions ˆ /∗ starts a potential multi-line comment which ends with a corresponding ∗/. Both /∗ and ∗/ are part of that comment and will not generate machine instructions.  the asterix (*) on lines 10 and 11 on the example below is not needed. It's there to make it more obvious that these lines are comments;  the start- and end- sequences can be on the same line. The code after the end sequence is part of the program code to be compiled; ˆ documentation strings start with triple forward slashes As an example, let's look at the code below and see the comments which are colored green (the coloring is automatically done by Visual Studio and is intended to help the developer to recognize the dierent code parts. It has no eect on the code itself and dierent color schemes are available): xix xx C# COMMENTS AND COMMAND DELIMITER Figure 6: A program with comments For the compiler, the actual program code for which machine instructions are generated looks like the screenshot below: Figure 7: The same program without the comments 0.6 C# command delimiter: ; Every programming language needs a way to separate one command from another: the compiler must know where a command ends and the next command starts. ˆ the C # command delimiter is the semi colon ; ˆ this command delimiter is introduced in C, and has been used in all C- based languages # like C , JAVA, JavaScript, C++,.. Demonstrated in the previous example screenshot which illustrated comments as well: ˆ a command can span multiple lines: it only ends when a semi colon is met; ˆ the same line can contain multiple commands: every command ends when a semi colon is met, after which a new command starts, potentially on the same line; ˆ indentation (white spaces before the actual command starts) can be used to increase readability, without changing the meaning of the program code; ; Although the same line can contain multiple instructions, seperated by , because of readability, most programs contain only one command on a line. 1 2 CHAPTER 1. VARIABLES AND DATATYPES Chapter 1 Variables and datatypes Figure 1.1: Variables and datatypes wordcloud 1.1. INTRODUCTION 3 1.1 Introduction Variables are names for places in program memory where values can be stored in and retrieved from. The datatype of the variable species expectations for the values put in or retrieved from these locations. A (Wikipedia:) datatype denes both the possible values and the possible expressions (usages) dened for these values. ˆ Statically typed languages like C # associate the datatype with a variable. This association is xed and can not change. The datatype associated with the variable is specied when the variable is dened; ˆ Dynamic languages like Python associate the datatype with the value found in the variable. The variable itself has no datatype and values with dierent datatypes can be moved to the same variable, which is not possible in the statically typed languages. When Object Orientation (OO) is introduced, we will be able to create new datatypes ourselves. # For now, we will discuss basic datatypes which are part of the programming language C. If you are unfamiliar with Visual Studio, you should read Visual Studio introduction rst. 4 CHAPTER 1. VARIABLES AND DATATYPES 1.2 C#: String datatype 1.2.1 String example Most programming languages start their documentation with a HelloWorld program , which puts the text Hello, World! # on the screen. This is exactly what the C default console application does for us: Figure 1.2: Default console application: "Hello, World!" 1.2.2 String values What is called text outside the programming context, is called a String within the programming world. Since String values and the supported expressions are what makes up the String datatype, we start by delving into the String values. There's a lot to be told concerning strings # # (text values) in C. A complete writeup can be found in C programming guide: Strings and string literals. The most important features for this course are written in this text. ˆ line 7, which writes the text value Hello, World to the console (=screen), species the String value to be written to the console between two double quotes. This String value consists of a sequence of characters.  the double quotes delimit the text and do not belong to that text themselves (text is the non technical synonym for String); * a double quote is one character and not two single quote characters;  a String value can contain up to two billion characters;  Visual Studio recognizes the text denition and colors it red, including the delimiters. This is just visualization by Visual Studio: it is not part of the source code and other IDE's might approach this dierently. * as you can see, other colors are used as well. Through this course, we will explain how these colors are used to identify dierent types of text in the source code; Terminology: values written in program code are called Wikipedia: literals. This applies to all values, not only String values. 1.2. C#: STRING DATATYPE 5 1.2.3 Special String values ˆ the empty string (a string which contains zero characters) is a valid string. It can be written as String.Empty or "" ; ˆ some character combinations inside a C# string value have a special meaning and behave in a special way: the resulting text is not the text you typed! If we want to include horizontal tabs, vertical tabs, move to a new line,.. in a String value, we insert so called escape sequences. The known escape sequences are dened here: String escape sequences ;  be sure to know the newline escape sequence. This escape sequence is used to move the remainder of the text value to the start of the next line (in old printer terminology: a carriage return + line feed). As the image below demonstrates, Visual Studio recognizes the escape sequences and puts them in a dierent color;  do the test: Figure 1.3: Example: escape sequences ˆ if you don't want the escape sequences to apply their special meaning, but they should simply be plain text, one can use so called verbatim text by prexing the starting text delimiter with @. As the image below demonstrates, Visual Studio recognizes the verbatim text, so no special coloring inside the string is applied:  do the test: Figure 1.4: Verbatim text  if you read the reference text, you will nd that the interpretation of two double quotes in verbatim text is still interpreted dierently from the written text. ˆ Raw string literals replace the need for escape sequences. This is relatively new and not available in Unity yet. Still, you are expected to know this! 6 CHAPTER 1. VARIABLES AND DATATYPES 1.2.4 String expressions Having described the String values in the previous subsection, we must address the possible String expressions to complete the String datatype. The screen-shot below illustrates how these expressions can be used: Figure 1.5: An incomplete list of string expressions In the code above, dierent instructions are written one after the other. The execution of this code happens one instruction at a time, the next one only starting when the previous one ends. This list above is very incomplete. Be sure to be comfortable with the list of String expressions below '(which is incomplete as well). Using the Visual Studio intellisense triggered when typing a dot (.) can make it much easier for you. It might be worth noting that the terms below are not explained here on purpose! You are strongly encouraged to look them up yourselves (ask Copilot or ChatGPT?) ˆ concatenation (the most important one); ˆ string interpolation; ˆ composite formatting (to complex for this course); ˆ retrieving a substring from a string value;  see what happens if the specied substring exceeds the original string itself; ˆ convert a string to it's uppercase or lowercase version; ˆ trim a string (removing leading or trailing characters); ˆ retrieve the length of a string; ˆ check whether a string contains a certain substring; ˆ check whether a string starts with a certain other string; ˆ reverse a string; 1.2. C#: STRING DATATYPE 7 1.2.5 String values are immutable String value's never change, they are immutable ! This means that every manipulation of a String value which results in a changed String value actually creates a new String value! The documentation for this is found in Immutability of strings. If you need to perform a lot of string manipulations, one might consider using the StringBuilder datatype for eciency reasons (not part of this course). Figure 1.6: Immutable strings: 5 strings are created The ve strings created based on the above code: ˆ this is a string and - (a string consisting of the dash character), both created at compile- time; ˆ the substring yields the new String s is a st, created at run-time; ˆ ToUpper yields the new String S IS A ST, created at run-time; ˆ the concatenation yields the new String S IS A ST-, created at run-time; 1.2.6 String variables The previous example used xed text values. The example below demonstrates the concept of String variables, the explanation is written below: # Figure 1.7: Hello world demonstrating text variables (C code) Figure 1.8: Hello world demonstrating text variable (output) 8 CHAPTER 1. VARIABLES AND DATATYPES ˆ line 7: dene a variable s of type string and immediately assign a text value to it. More information concerning an assignment can be found in Variable assignment;  the denition of a variable is a command which starts with the name of the variables datatype (for line 7: string ) followed by the name of the variable (for line 7: s ). * in C # , only values of the datatype specied in the denition of the variable can be assigned to the variable; * for local variables (a local variable is dened within a method (methods are introduced here)) the name of the datatype can be replaced by the keyword var # to implicitly type the local variable. I advice against this when you start C programming;  C # uses both string (line 7) and String (line 11) to designate the datatype associated with text values. The rst is a keyword, the second (with capital) the name of a (data) type. For most practical concerns, they are identical; * since keywords and type names are colored dierently in Visual Studio, string and String will have a dierent color; ˆ line 8: retrieve the value in this variable and write it to the console. Note that the variable name s is not enclosed by double quotation characters. If that were the case, it would be the text s instead of the content found in the variable s;  in C # , a variable name in the left side of an assignment refers to the memory location. In all other situations, the variable name refers to the value found at this memory location. Line 14 uses the values found in s1 and s2, while line 12 moves a value to the memorylocation created for the variable s1 declaration at line 11; ˆ line 9: put a new text value in the variable s. The old value is overwritten and can not be retrieved anymore. That's why s is called a variable: it's content might vary over time; ˆ line 10: write the content of variable s to the screen. Although the command at line 10 is an identical copy of the command at line 8, the output written is dierent because the content of the variable changed between the two executions. ˆ line 11: one command can dene multiple variables of the same type;  observe that we used the String datatype name which is a synonym (for now) for the string keyword used in line 7 (the class name and the keyword have a dierent color in Visual Studio);  although not shown in the example, the multiple variables dened in line 11 can also be initialized in line 11; 1.2.7 Variable assignment Assigning a value to a variable (or: placing a value in a variables memorylocation) is called an assignment #. In C , an assignment instruction is coded using the equal sign character. Don't = 1.3. C#: INT DATATYPE 9 confuse this with the mathematical meaning which tests for equality! variablename = valueexpression; ˆ the left hand side of the assignment must be a variable name; ˆ the right hand side of the assignment must be some program code which yields a value of a type which can be assigned to the variable. This right hand side value is determined as the rst step of the assignment. This right hand side is a so called expression. For the time being, we stick to the possibilities formulated below:  a literal (constant) of a correct type;  a variable name of the correct type. In this case, the content of this right hand side variable is used to be placed in the left hand side variable (both variable names might be the same, in which case the assignment is pointless, since it replaces a value with the same value)  a calculation which yields a value of a correct datatype. The values used by this calculation are itself expressions again (so, the denition is recursive). ˆ the second and nal step of an assignment copies the calculated right hand side value in the variable memory location; ˆ an assignment actually results in the value being assigned, which makes an assignment an expression as well! This makes the commands below correct: String s1, s2, s3; s1 = s2 = s3 = "abc"; which assigns the text "abc" to the variables s1, s2 and s3. Examples: Figure 1.9: String assignment examples 1.3 C#: int datatype 1.3.1 int example Computers are good at performing mathematical calculations. Just like in math, C # makes the dierence between dierent types of numbers. Integer values (Dutch: gehele getallen) are dened by the int datatype. The example below demonstrates the denition and usage of some int values and operations: 10 CHAPTER 1. VARIABLES AND DATATYPES Figure 1.10: Int examples The Console.WriteLine instruction automatically converts the int- values to their corresponding text value (which is not trivial). This conversion takes into account the language settings of the device which runs the program. English installations use. as a fraction separator, while Dutch installations use a. , For completeness' sake, it's worth noting that other datatypes dening integer values exist as well: uint, byte,.. to name a few. Characteristics of the integral types lists most, but let's stick to int. The dierent types dening integer values mainly dier in the range of values they allow, the operations dened are similar. 1.3.2 int values 1.3.2.1 int literals When we write int literals (values) in our program, we must adhere to the following rules: ˆ A positive int literal consists of a combination of digits: 123; ˆ A negative int literal consists of the minus sign followed by a positive literal: -123 ˆ int values are registered in 32 bit memory spaces: they are limited in range (from -2 billion to +2 billion). This might seem a lot, but some people possess more money than you can register in a int :) ˆ other integer datatypes exist as well. They allow for other values than the int- datatype. For instance:  byte integer values are stored in a byte (8 bits) and so can only range from 0 to 255;  uint integer values don't allow negative values, but allow positive numbers up to 4 billion; 1.3.2.2 Special int value notations There are some notation variations possible for int literals, eg when you want to describe the integer value in a hexadecimal or binary way, a prex notation is used. A postx notation can be used to inform the compiler the numeric value is of a specic integer datatype (like long). A complete description concerning the notation of integer values (literals) can be found in Integer literals but is outside the scope of this course. 1.3. C#: INT DATATYPE 11 Figure 1.11: Hexadecimal and binary notation example ˆ the binary notation example demonstrates the use of the underscore as the digit separator. The digit separator is ignored by the compiler, but improves readability. ˆ the digit separator can be used in any numerical literal, and is by no means restricted to the binary notation ˆ the digit separator can be place anywhere in the literal. Of course, we prefer a position which enhances readability!  int j = 10_00_0; puts 10 000 in the variable j, but doesn't enhance readability;  int j = 10_000; puts 10 000 in the variable j, and enhances readability. 1.3.2.3 Special int values int values take up 4 bytes of memory, so innite numbers are not possible. The maximum and minimum int value can be obtained as follows: Figure 1.12: int minimum and maximum values 1.3.2.4 Random int values Figure 1.13: Random int values Some remarks can be made here: ˆ the random generator is a pseudo random generator. This means that theoretically, it's not completely random, but for all practical purposes, the randomness is OK; ˆ the upper-bound is not part of the possible values! 12 CHAPTER 1. VARIABLES AND DATATYPES 1.3.3 int operations 1.3.3.1 Binary int operators Binary int operators operate with two int operands, hence the name. The traditional operators are available: +, -, *, / Mind the following: ˆ the division is an int division. This means that the result of an int division is an other int: 7/4 yields 1 and not 1.75 as some might expect;  If the program needs numerical operations which yield fractional results, then the oat datatype must be used. ˆ % is the remainder operation: 7%4 = 3 Remark: division by 0 for int values generates a run time error: your program will crash! 1.3.3.2 Unary int operators ˆ Writing a - in front of an int expression multiplies it by -1. This makes - a prex notation unary operator!  int i = -3;  int j = -i; ˆ The unary int operators ++ and -- need int variables to work with, so they'll be explained in Unary int operators: ++ and --. 1.3.3.3 Operator precedence As we all know, some operators have a higher priority than others. The complete C# list can be found here. As expected: ˆ multiplication and division have equal priority, higher than addition and subtraction (see the table); ˆ check the priority of the remainder operator in the table; ˆ in case operators have equal priority, they are evaluated left to right (with some exceptions like assignments); ˆ use braces () to change priority of operations:  () operands are evaluated completely before they take part in an operation; ˆ these rules apply to all operators, not just numerical ones! Predict the outcome of the following statements: Console.WriteLine("3+4="+3+4); Console.WriteLine(("3+4="+3)+4); Console.WriteLine("3+4="+(3+4)); 1.3. C#: INT DATATYPE 13 1.3.3.4 int datatype functionality The int datatype provides some functionality through the dot- notation. These are not strictly operations since they don't use an operator, but they provide calculated int values, which interests us. Figure 1.14: int datatype functionality ˆ see the video 1.3.4 int values are immutable Int values are immutable just like String values: they can not change. This might have seemed weird for String values, but is much more intuitive for numeric values: a 7 remains a 7, even if you add a 1: the resulting 8 is an other value! Well, this is how one should think about the immutable String values: they don't change, and if you obtain an other String value, then it really is a new value, not a changed previous one! 1.3.5 int variables 1.3.5.1 Declaration, assignment, use Figure 1.15: Performing operations using int variables 14 CHAPTER 1. VARIABLES AND DATATYPES This is similar to the String variables: ˆ a variable denition starts with the type- name, in this case int ; ˆ int is actually a keyword. The type- name it corresponds to is Int32 (just like string corresponds to String ) ˆ variables can be initialized immediately, but this is not required; ˆ replacing the content of a variable overwrites the old value which then is lost forever; 1.3.5.2 Compound assignment Figure 1.16: Compound assignment: + ˆ The statement i += 3; is actually a shorthand for i = i + 3; ˆ The other binary int operators can be used in a similar notation These operations combine the mathematical operation with the assignment operation, hence the name compound operation. 1.3.5.3 Unary int operators: ++ and -- Unary int operators operate with one int operand, hence the name. Figure 1.17: ++: prex and postx ˆ if the unary ++ operator is used in postx notation (written after the variable name it applies to), the original content of the variable is used in the calculations, after which the content of the variable is increased by 1; ˆ if the unary ++ operator is used in prex notation (written before the variable name it applies to), the content of the variable is increased by 1 before the variable content is used in the calculations; ˆ -- behaves in a similar way but subtracts 1 from the variable 1.4. C#: FLOAT DATATYPE 15 1.4 C#: oat datatype oat adheres to the IEEE 754 standard. This standard is important because it species how the datatype behaves in edge cases, like a division by zero. For this course, it's irrelevant information. 1.4.1 oat example Many mathematical operations work with non integer values, values with a fractional part. The default in C # for this is the double datatype (needs 8 bytes), but in game programming, we use the oat datatype (needs 4 bytes)! ˆ oat values are preferred in gaming since they are accurate enough for what we do, and only take up half the memory space of a double. Since the 3D models used in games can contain thousands of vertices, each having 3 coordinates with a non integer value, using oats instead of doubles reduces the memory consumption by half ! Figure 1.18: Float examples 1.4.2 oat values 1.4.2.1 oat literals As you can see from the example, oat values adhere to the following rules: ˆ a oat literal consists of digits in which one decimal point is found and which are suxed with f (or F). Use the prex - to indicate a negative value;  the decimal point is really a. and not language settings dependent: in your programming code, the decimal point is always a point and not a comma, even if you have Dutch language settings; * if you generate output or read user input, then language settings are applied, but not in your programming code!  oat values end with the sux 'f '. Without sux f, the default datatype for fractional values is used, which is double. Since a double takes up 8 bytes, it can not be put in a variable of type oat (which reserves a memory space of 4 bytes). ˆ the underscore can be used as a digit separator for oat literals just like it is for int literals. 16 CHAPTER 1. VARIABLES AND DATATYPES It's important to realize that oat values can not be put in int variables. Although both take up 4 bytes, the interpretation of the byte content is very dierent! 1.4.2.2 oat value rounding errors All numerical values we write in code are translated to binary values: ones and zeroes. This comes with some unexpected rounding errors. For instance, it's impossible to put a faultless 0.1f value in a nite binary representation: it will always come with some rounding error. If you would add 0.001f a thousand times together, the result will not be 1.0f. 1.4.2.3 Special oat value notations ˆ Float literals support the scientic notation, which I have never used so far. 1.4.2.4 Special oat values Similar to the int special values. 1.4.2.5 Random oat values Random oat values can be obtained by casting random double values to oats. Both casting and random double are discussed further down this chapter. 1.4.3 oat operations 1.4.3.1 Numeric oat operations The intuitively expected behavior applies. The output below is generated by the example above: Figure 1.19: Float examples:output ˆ as you can see, the output uses my Dutch language settings, using a comma instead of a dot as the decimal separator; ˆ although the second output looks like an int value (it shows no fractional part), it really is a oat. The text representation of the zero fractional part (8.0) is not shown; ˆ the division and remainder both yield a oat value; 1.4. C#: FLOAT DATATYPE 17 Remark: division by 0 for oat values does not generate a run time error (like division by 0 for int values). Instead oat. NaN is the result (NaN is short for Not A Number, and oat.NaN is a valid oat value) 1.4.3.2 Numeric operations which mix int and oat values If you mix int and oat values in a numeric operation, the int value is implicitly (automatically) converted to a oat value rst, after which the operation is an operation between oat values, which of course yields a oat value. ˆ the opposite would not be safe: converting a oat to an int (by dropping the fractional part: truncation) introduces loss of precision. Converting from int to oat does not introduce a loss of precision: adding the fractional part.0 is perfectly legit.  well, the above is not completely true: errors can occur when converting a (big) int to a oat and back. The example below illustrates the problem in both directions: Figure 1.20: int to oat to int conversion issues 1.4.3.3 oat datatype functionality Use the dot- notation (like we did for int datatype functionality) to retrieve the available functionality. 1.4.4 oat variables Again, the denition of variables follows the same pattern: rst the datatype, then the variable name, potentially initializing the variable: Figure 1.21: Float variables 18 CHAPTER 1. VARIABLES AND DATATYPES ˆ oat is a keyword (just like string and int). The corresponding datatype is Single. Single # is hardly ever used in C programming. ˆ line 8: some predened oat constants (like π) and functions (sin, cos,..) exist. These can be accessed through the MathF class; ˆ line 9 works in two steps:  the calculated value is an int- value, since the division of 2 int values yields an int (in this case: 0);  the variable is dened as a oat. Since the int can be converted to a oat without loss of precision, this happens automatically (implicitly);  although q1 is a oat, it's value is 0.0f and not 0.75f as you might have expected. ˆ line 10 yields a oat value (see Operations which mix int and oat values) ˆ line 11: yields an error since the default datatype for a fractional value is a double (there is no f sux written). Since a double can not be converted to a oat without loosing precision, this conversion can not be performed automatically, which in turn results in an error. 1.5 C#: double datatype double is a very important datatype in C #, just not so in game programming. doubles behave very similar to oats, with some exceptions: ˆ double is a keyword, Double is its corresponding datatype; ˆ doubles take up double the space of a oat; ˆ numerical literals with a fractional part and without sux are automatically doubles! forget the sux and you end up with a double! ˆ Math is het double equivalent van MathF and provides double constants and functions; ˆ numerical operations which mix int, oat and double convert all values to double, after which double operations are executed, which yield a double. 1.5.1 double values Figure 1.22: Random double values 1.6. C#: DECIMAL DATATYPE 19 ˆ Random.Shared only supports random double values in the range [0,1[; ˆ generating random double values in an other range [start, end[ is a nice exercise! 1.6 C#: decimal datatype The decimal datatype also allows numbers with a fractional part (like oat and double), but has an even better precision. The decimal datatype should be used when no rounding errors are allowed. This might be the case in nancial computations, but is not relevant for this course. 1.7 Rounding errors Figure 1.23: Rounding In C #, numbers are internally represented in a binary format. A oat number (oat is a synonym for System.Single) complies with the IEC 60559:1989 (IEEE 754) standard for binary oating-point arithmetic (such a standard describes how this type should perform during arithmetical operations). 1 √ Just like decimal numbers can't completely represent 3 , π, 2,.., binary numbers can not exactly represent every non- integer number with a nite decimal representation. Some numbers with a nit decimal representation don't have a nite binary respresentation! In these cases, the arithmetic operations can result in unexpected values: since the value do not exactly match our decimal representation, the result won't either. If you need correct decimal results, use the decimal class. For more information concerning oating arithmetic (outside the scope of this course), I refer to C # in depth: Binary oating point and.NET 20 CHAPTER 1. VARIABLES AND DATATYPES 1.8 C#: char datatype: self study The char datatype is available in most programming languages. Look up the char-datatype in # a C context, and be sure to know the following elements: ˆ what values are possible? how are they written?  does visual studio apply some specic coloring? ˆ what operations are supported? ˆ how to declare variables of the char datatype? Be sure to write a program which tests your ndings! 1.9 Tuple data types Sometimes a complex value consists of a composition of dierent values combined. The classical solution (which we will only teach later in the course) would be to dene a data type (class) which can hold all these values, and return an instance of this class. A more lightweight solution, tting for this moment, is the use of tuples. 1.9.1 Tuple Tuple (Wikipedia) : a tuple is an ordered list of values. Typically, the values are written between braces () and separated by comma's. The combination of these values results in something meaningful. Some examples: ˆ (4,7): an X coordinate (4) and a Y coordinate (7), identifying up a 2D vertex; ˆ (12, 30, 15): a time of day which consists of an hour (12), minute (30) and seconds (15) combination. The order is important for a correct interpretation: (30, 12,15) indicates a dierent (invalid) time of day; ˆ (12, 30, 15): an (X,Y,Z) combination forming a 3D vertex. Note that this value is identical to the previous one, only the interpretation is dierent! ˆ (Platform Development 1, Jef Daels): a course (Platform development 1) and one of its teacher (Jef Daels); ˆ (Primoz Roglic,Jonas Vingegaard,Christophe Laporte,Sepp Kuss,Wout van Aert,Steven Kruijswijk,Tiesj Benoot,Nathan Van Hooydonck): a cycling team for the Tour de France 2022, with its 8 cyclists; ˆ (Kortrijk,8500): a town name (Kortrijk) and its postal code (8500);  as shown by this example, the values in the tuple can be of a dierent type themselves. In the examples above, for simplicities sake, the values in the tuples are simple values. In real life, they can be more complex (which is hard to demonstrate at this time of the course). 1.9. TUPLE DATA TYPES 21 1.9.2 Tuple data types and variables Since a tuple is a value, it must have a corresponding data type. The data type is formulated between braces () and enumerates the data types of its components, separated by comma's, as demonstrated below: Figure 1.24: Tuple variable denition ˆ lines 7 and 10 each dene a variable which is a tuple. Both tuples are of a dierent data type. Observe how the data type of these variables is constructed (matching the values to the right)! ˆ line 8, 11: each value in the tuple can be addressed using the dot-notation: vertex.Item1, town.name,..  write the tuple variable name (eg. vertex)  add a dot (.)  add the eld name (Item1, Item2) ˆ As you can see from the code above, the values in the tuple get their names based on their position in the tuple: Item1, Item2,.. 1.9.2.1 var keyword When the type of a value can be determined (inferred) by the compiler (almost always), a variable can be implicitly typed using the var keyword. In the example below, each line contains the comment of the resulting variable data-type: 22 CHAPTER 1. VARIABLES AND DATATYPES Figure 1.25: var keyword: examples + debug demo ˆ using the var keyword still assigns a type to the variable. This type is not coded explictly by the programmer, but derived from the assigned value by the compiler! ˆ when stopped at a breakpoint (line 16), the locals window (below the code) shows us the types associated with the local variables; ˆ interestingly, the types for t1 and t2 are dierent, because of the named elds in the latter (see the next section: tuple eld names. Still, they are compatible: t1 can be assigned to t2 and vice-verse; 1.9.3 Tuple eld names To more clearly convey the meaning of each value in the tuple, one can provide meaningful names for each eld in the tuple data type (Tuple eld names ): Figure 1.26: Tuple variable denition with eld names ˆ line 7, 10: provides meaningful names to the elds of the tuple data-type denition; ˆ line 8, 11: use the meaningful names when addressing the elds in the tuple; ˆ you can still use the default names (Item1,..), which is discouraged; 1.10. CONSTANTS 23 ˆ as you can see from the screenshot, the intellisense within Visual Studio knows the names of the elds you provided in the data-type denition! As the code below demonstrates, if the variable type denition and the assigned value use dierent eld names, the variable type denition takes precedence (and the compiler generates a warning): Figure 1.27: Tuple eld name conicts (warning) 1.9.4 Deconstructing tuples Deconstructing tuples is a fancy way to say: splitting tuples into its dierent values. This is realized through pattern matching as shown below: ˆ (int X, int Y) = (4,7);  after this statement, X holds the value 4, Y holds the value 7;  the tuple type denition to the left of the assignment must hold as many variables as the number of elds in the tuple to the right;  of course, the values in the tuple- value must match the types of the variables in the tuple type denition; ˆ (int hour, int minute, int seconds) = (30,12,15)  after this statement, hour holds 30, minute holds 12, seconds holds 15  no test is executed to check whether the values are logically correct (hour equal to 30 is logically incorrect) ˆ (string course, int studypoints) = (Platform Development 1, 9)  be sure to use the correct datatypes when decomposing: the rst variable (course) must be a string, the second (studypoints) an int; This will be much more important next week, when we return tuples as the result of a method call! 1.10 Constants Variables are named memory places which contain values which might change during the execution of the program. If the value is not supposed to change, one can use a constant (which as the name suggest has a constant value: it cannot be changed). The technical description can be found here. An example is shown below: 24 CHAPTER 1. VARIABLES AND DATATYPES Figure 1.28: C#constants ˆ the above code denes 4 constants  a constant denition is very much like a variable denition, but prexed using the keyword const  the rst three get the value from a literal (an unnamed constant)  the fourth one is calculated using other constants (in this case all named, but they can be unnamed as well). * You can't use variables to calculate a constant. ˆ as line 18 demonstrates, you can't assign a value to a constant (the message stipulates which kind of stu you can assign to, a constant is not one of them) ˆ if you look at the intellisense in code, Math.PI is dened as a constant as well: Figure 1.29: Math.PI constant Using named constants has some advantages: ˆ the name of the constant is easier to remember (GRAVITY instead of 9.81); ˆ the associated value is always the same. Without constants, some programmer might use 9.81 for gravity, while an other uses 9.80665. If this were the case, similar calculations using dierent values would yield dierent results; ˆ dening a value as constant gives the compiler optimization possibilities 1.11. DATATYPE TRANSFORMATIONS 25 1.11 Datatype transformations 1.11.1 Datatype transformation terminology The terminology concerning Datatype transformation mainly uses the terms cast and conversion. If you look them up on the internet, you'll nd dierent, conicting descriptions. For the purpose of this course and exams, we stick to the interpretation found in C# type casting # (w3schools which diers slightly from Casting and type conversions (C Programming Guide) (I prefer the w3schools one it agrees with most programmers I consulted). Code examples are provided for each transformation when discussed in detail. ˆ Type casting is when you assign a value of one data type to another type. This can be both implicit or explicit.  explicit type casting is performed by writing a cast expression ;  once we introduce polymorphism, non numerical cast expressions will be introduced as well. ˆ implicit type casting from a smaller type to a bigger type is possible, not explicitly writing the cast expression;  one immediately wonders what a smaller or bigger datatype is. An incomplete sorting of datatypes: int is smaller than oat which is smaller than double. Datatype A is smaller than datatype B if the A value can be interpreted in B without loosing information. ˆ Type conversion is the process of executing methods to go from a value of a datatype to a value of an other datatype. A nice example is int.Parse which yields an int value for a string value. 1.11.2 Type casting As explained in w3schools: type casting : type casting occurs when you assign a value of one datatype to another datatype. At this part of the course, we will restrict ourselves to numerical types, although type casting can be applied to other types as well in the context of polymorphism. 26 CHAPTER 1. VARIABLES AND DATATYPES 1.11.2.1 Explicit type casting Figure 1.30: Explicit casts illustrated ˆ explicit type casting is written by the programmer by writing a cast expression : the destination type between round braces in front of the value which needs to be transformed (eg: (oat)i ). This cast expression yields a value of the destination type; ˆ the cast expression has higher priority than the numeric operations. Line 19 applies the typecast on the double 3.14 before performing the addition;  braces can be used to combine a numerical operation to 1 value before the type cast is applied (line 18); 1.11.2.2 Implicit type casting Figure 1.31: Implicit casts illustrated ˆ C# can perform implicit typecasts if no precision is lost: int to oat, int to double and oat to double are allowed and illustrated in the screenshot above; ˆ In general, implicit type casting between numeric types is allowed if a smaller size type is changed to a bigger size type (oat is considered bigger than int, although both take up 4 bytes) : int < oat < double. ˆ implicit type casting from a bigger type to a smaller one is not allowed. This is why line 16 results in an error (read the error message!). 1.11. DATATYPE TRANSFORMATIONS 27  as you can read from the error message, in this situation C # uses the term convert instead of the term cast 1.11.3 Conversion Conversion is the process which transforms a value to a corresponding value of a non compatible datatype without performing a cast. Examples of this are the conversion of the string 123 to the integer 123 and vice versa. This typically calls a method, which will be introduced here. Figure 1.32: Type conversions illustrated ˆ many datatypes provide a Parse method to support converting a string to a value of that datatype; ˆ the Convert class provides an alternative way to call Parse methods; ˆ when parsing text to numerical values, culture info (country settings) applies. With Dutch country settings, the decimal dot is actually a comma. With English country settings, the decimal dot is really a dot. This implies that naive parsing of the same text can yield dierent results on dierent installations, depending on the country settings outside the program.  use the invariant culture (which is some English culture) to avoid parsing the same text in a dierent way (Visual Studio always parses numbers in your programs with the invariant culture). Of course, user input in a text eld should be parsed with the country settings of the user. ˆ when a string is concatenated with something else, this second value is automatically converted to it's string value (black magic, explained in the chapters concerning object orientation). That's why, at line 28, s will contain the text representation of the int found in variable i, appended to the empty string. 28 CHAPTER 1. VARIABLES AND DATATYPES ˆ as lines 30 and 31 demonstrate, type conversions allow to change values to a destination type which type casting does not support. I would have been happier if the error message used the term 'cast' instead of 'convert'. Remark: the.NET documentation calls all data transformations conversions, and type casts are a special case of conversion. This is not the naming we follow in this course! 1.12 Variable naming When coming up with names for variables, we must adhere to both technical restrictions and conventions. ˆ C # language reference: 6.4.3 Identiers (don't memorize this for the exam) denes how a correct variable name can be formulated. For this course, stick to:  a (variable) name is a combination of (not all are required) alphabetical characters (lower and upper case), digits and the underscore (so you can't have a space in a variable name);  a (variable) name can not start with a digit  to declare a name which is identical to a keyword, prex the variable name with @  names in C # are case sensitive * the variable name fName indicates a variable dierent from the variable name fname ! 1.13.NET framework When developing a program, one needs two components: the programming language and # the programming environment. C is a programming language: it denes a valid syntax to code instructions which will ultimately be translated to executable code. The programming environment provides us with basic elements the programming language can work with. Depending on the problem one tries to solve, one or the other programming environment might be more appropriate. Let's make this more concrete: ˆ MonoGame is an environment which provides features to implement 2D games. We will # use C as the programming language for this, but other languages (eg. VB.NET) could have been chosen as well; ˆ Unity is an environment which provides features to implement 3D games. We will again # use C as the programming language for this, but other languages could have been chosen; ˆ.NET framework is an environment developed to support general programming. It is available on dierent platforms (Windows, Linux, Mac-OS,..) which allows us to write C # programs which run on these platforms; 1.14. CLEAN CODE 29  the.NET framework provides the datatypes Double, Integer.. which correspond # with the C keywords double, int,..  the.NET framework provides classes for le-IO  the.NET framework provides classes for HTTP ... Those environments are not mutually exclusive: when you develop in Unity, you get both the.NET framework and the Unity environment. Even more, the environment you have can be extended by installing extra libraries. It's important to realize the dierence between the programming language and the environment: the programming language denes syntax, the environment denes the possible elements this syntax can be applied to. 1.14 Clean code Inspiration and title for this section is found in the book Clean Code: A Handbook of Agile Software Craftsmanship. Not all elements from the book will be introduced and the topics are introduced in the chapter they apply to: the concepts are that important that we want to introduce them from the start, but some topics are only relevant in a more complex situation than the rst lessons can oer. 1.14.1 Concerning variable names ˆ Use intention revealing names: if a name requires a comment explaining its content, then the name does not reveal it's intent and should be changed into a better name; ˆ Avoid disinformation: if a name suggests a dierent intent then the real one, the problem is even bigger; ˆ Make meaningful distinctions: two similar variable names should, from the name, demonstrate their intended distinction:  rstName  fName If you use rstName for the identity card rst name and fname for the nickname that person has in your system, then you are introducing troubles from the start: no programmer maintaining the code after you will grasp this distinction from the name: there is no meaningful distinction between the two variable names; ˆ Use pronounceable names: this one is important when you have a conversation/discussion with colleagues concerning your code. It's only fun once if you have to discuss an unpronounceable name :) 30 CHAPTER 1. VARIABLES AND DATATYPES ˆ Don't use abbreviations. Most programmers will be tempted to not follow this rule. Abbreviations which have become known to all (eg. HTML) can be used in a variable name. Abbreviated names probably do not apply the previous rule concerning intention revealing;  Visual Studio makes name refactoring that easy that failing to do so is just inexcusable; ˆ Follow the naming standards of your environment. Dierent platforms use dierent # naming standards (historically grown?). In C (and.NET) local variable names should:  start with a character (don't start with an underscore!);  use lowerCamelCasing (you should look up what this means, it's important!). This is a convention which must be followed during this course! 1.14.2 Concerning magic numbers Magic numbers are values (probably but not necessarily numeric) which occur in the program code without being placed in a variabel with a meaningfull name. The disadvantage of this is threefold: ˆ the calculation is probably less clear when values are used instead of meaningful names; ˆ when the values must be updated, one must nd every occurrence of this value and update it; ˆ when changing a value through your code, it might be that the same value has a dierent meaning and not both of them must be changed Figure 1.33: Magic numbers illustrated Both sets of code (top two and bottom ve) calculate the topleft position of a rectangle which is placed at the center of the screen. The rectangle size is 10% of the screen size. The rst two ones are much harder to update than the last ve because of the magic numbers: 1.15. CHAPTER TAKE AWAYS 31 ˆ if the calculation needs to change, I would prefer the ve lines because the purpose of each element of the calculation is clear, which is not the case in the top two lines; ˆ if other calculations would need the screen dimensions as well, we can just use the variables; ˆ if the screen width changes, one only needs to put an other value in the variable. When coding magic numbers, changing the screen width requires us to nd every occurrence and change it;  performing a global change would not be advisable since the same magic number (800) is used for the height as well, which should not be changed. This does not mean that every number must be put in a variable. When one wants half of a number, one divides by 2! 1.15 Chapter take aways ˆ datatypes dene potential values and the supported transformations on these values; ˆ multiple numeric datatypes exist! ˆ multiple values can be combined into a new value, using tuples; ˆ literals are written dierently, depending on the datatype; ˆ variable denitions include the type denition; ˆ in this course, we make a distinction between type casts and conversions; ˆ when working with variables, some clean code rules apply; ˆ you had to look up the char datatype yourself: values and transformations! 1.16 Technical references ˆ Tuple types (C # reference) ˆ Deconstructing tuples and other types ˆ var (C# reference) 1.17 Supportive videos ˆ Leho ˆ Microsoft Virtual Academy: C# for beginners 32 CHAPTER 1. VARIABLES AND DATATYPES 33 34 CHAPTER 2. METHODS Chapter 2 Methods Figure 2.1: Methods wordcloud 2.1. METHODS INTRODUCTION 35 2.1 Methods introduction If you created a solution for the exercises of the previous chapters, you will have noticed some repetitive coding: if you need to calculate the MVP score of multiple heroes, you wrote the same logic, processing dierent values for each of the heroes. This repetitive execution of the same logic with dierent values is very common in programming. Figure 2.2: MVP calculations as learned in previous chapters ˆ imagine having to code this for 100 heroes: create 100 copies and change the values; ˆ imagine what happens if you coded this for 100 heroes, after which the calculation logic changes to something else: you would need to update 100 copies! The code above can be replaced by the code below: Figure 2.3: MVP calculations using a function 36 CHAPTER 2. METHODS ˆ every extra hero introduces two extra lines. We could have included the writeline in the function logic, but for me, calculating a value and using this value (to write it in the console) are two very distinct things, which I keep separate;  it's still a lot of work when you have to process 100 heroes. This will be solved in the chapter introducing iterations. ˆ if the calculation logic changes, you only have to change it at one position: within the method. 2.2 Method denition A method denition consists of a method header followed by a method body, each introduced in it's own subsection. 2.2.1 Method header Although we will add some other keywords a bit further down the text, a method header denition boils down to the following: returntype methodname(datatype1 parameter1, datatype2 parameter2,..) ˆ the return type can be any datatype: oat, string, int,... Of course, tuple datatypes are allowed as well!  if a return type is specied, the method must return a value of this type. A method returns a value using the return keyword;  if the method returns nothing (no return keyword is coded in the method body), the return type must be void ; * if the return type is void, the method is not allowed to return a value ˆ based on the return type, methods can be divided in two groups:  if the return type isvoid , the method is called a routine;  if the return type diers from void, the method is called a function; ˆ the methodname should, by convention, be written in Pascal casing (this is not lowerCamelCasing, so you might want to look it up); ˆ the parameter list is a comma separated list of parameters between braces ();  even if the parameterlist is empty, the braces must be written;  every parameter is actually a variable denition: a datatype followed by a name. Normal variable naming conventions apply;  the parameters in the methodheader are called formal parameter s; 2.2. METHOD DEFINITION 37 So for the function dened in the previous screenshot, the method header is shown below: Figure 2.4: MVP function header ˆ ignore the static keyword for the time being; ˆ the returntype specied is oat, which obviously means that only a oat value can be returned as a result; ˆ the function name GetMVPScore adheres to the Pascal casing; ˆ the function has four parameters:  the rst parameter is a tuple, containing three int values to describe a heroes' statistics;  then three oat parameters describing the maximum values for each of the statistics. Remarks: ˆ parameter denitions allow for more keywords than is explained here; 2.2.1.1 Optional arguments The formal parameters in the method header allow to provide values to the method when it is executed. Some method headers provide default values for the formal parameters in the header. If this is the case, the optional argument is not required, and the default value is used if missing. ˆ all optional parameters must be coded a the end of the parameter list in the method header! Figure 2.5: Default parameter values ˆ since grades are normally between 0 and 20 (both included), the default max grade value which must not be provided (line 18) and if missing, we assume it's 20; ˆ if the calculation needs another maximum value, it can be provided as the second argument in which case the default value is ignored (line 19) 38 CHAPTER 2. METHODS 2.2.2 Method body A methodbody is a code block, which is written as follows: ˆ the code block is enclosed by curly braces ; ˆ the code block contains statements, which are separated from each other using the semi colon;  these commands are executed one after the other, starting at the top of the method and moving down to its end;  these commands can be other method calls; ˆ if the method has a return type dierent from void, the method must code a return statement, which returns a value of the return type;  executing the return statement ends the method execution. If any commands are coded after this return statement, they will nog be executed! ˆ two methods should not overlap: a method denition should be completed before an other method denition starts (internal method denitions are the exception); Remark: the above is a simplication of the complexer possibilities in C #: ˆ it's possible to nest other methods within a method (not for this course); ˆ one can dene anonymous functions through lambda expressions; ˆ... The method body is written directly after the method header. 2.3 Calling a method 2.3.1 How to call a method with positional arguments When the program must execute the logic dened in a method, the program must call the method: ˆ write the method name and provide the needed values between round braces ();  every formal argument (parameter) in the method header must be provided a value for. These provided values are called argument s or actual parameter s; * the actual parameter is an expression: it yields a value. So literals, variables, operations and function-calls apply;  the order of the arguments must match the order of the formal parameters in the method header: the position is important. That's why they are called positional arguments ; 2.3. CALLING A METHOD 39  the datatype of the provided arguments must match the datatype of the formal parameter, or an implicit cast must be available; * one can consider the parameter to be a variable of the method, which get's initialized with the provided actual parameter (argument).  there is no relation between (variable) names used while calling a method and the formal parameter names; ˆ remember from Default values for formal parameters, some method header denitions allow to omit actual parameters when a default argument value is specied in the methodheader The above is illustrated in the video DAE_PD1.Eng.W2 0 argument matching.mp4. Figure 2.6: Teaser from the video DAE_PD1.Eng.W2 0 argument matching.mp4 If the method called is a function (a method with a non void result type), the method call can be written everywhere a value of the return type is expected: a function call is an expression. The calculated value is used where the function call is written. Since a method can be called, a method can be seen as a new instruction added to the program. Developing these methods is key in good programming! 2.3.2 How to call a method with named arguments It's possible to list the arguments by adding the formal parameter name plus colon before the actual parameter: named arguments. Some technical requirements apply when mixing named and positional arguments. # The screenshot below is taken from Named and Optional Arguments (C Programming Guide) Figure 2.7: Named arguments 40 CHAPTER 2. METHODS I myself almost never use named parameters. 2.4 C#: return keyword The return keyword is used in the body of a function to return the resulting value: ˆ the return statement species which value must be returned as the result of this execution. The type of the returned value must match the return type of the function; ˆ when the return statement is executed, the execution of the program leaves this method. It's impossible to return and continue this specic method execution; ˆ a method can contain multiple return statements, but this is only useful after selections are introduced; ˆ if the return type of the method is void , the return statement can be written, but should not specify a value; ˆ if no return statement is written in the method, it assumes a return without value at the end of the method body; 2.5 Nested arguments Any expression which yields a value of a correct type can be used as an argument, even other function calls: Figure 2.8: Nested arguments 2.6 Calling mechanisms Warning: the explanation below concerning the calling mechanisms is simplied and not completely correct. 2.6. CALLING MECHANISMS 41 Figure 2.9: Calling mechanisms ˆ by default, the calling mechanism is call by value : the argument (actual parameter) is copied to the formal parameter. The method body can only change the formal parameter value, which has no eect on the actual parameter (since it is a copy). This is a simplication which will be addressed in Stack and heap; ˆ when adding the keyword ref , the calling mechanism is call by reference and the actual parameter must include the ref keyword as well. This uses the actual parameter in the method body and not a copy! Changes to the formal parameter will be reected in the actual parameter! This is a simplication which will be addressed in Stack and heap;  the consequences of being able to change the argument is that important that both the denition of the method and the caller of the method must specify the ref keyword, implying that both the caller and the method know that changes to the argument might be applied;  the out keyword is similar to the ref keyword but doesn't require the argument to be initialized. The out keyword is used in the TryParse method, introduced in the Selections chapter;  I don't expect you to use the call by reference when coding your own methods in this course. ˆ as the image shows, ref arguments must be variables (line 14)! More variations are possible. If you want to know more about them, have a look at Reference parameters. 42 CHAPTER 2. METHODS 2.7 Revisiting the method example Figure 2.10: MVP calculations using a function: complete program ˆ the function denition for GetMVPScore starts at line 27 and ends at line 33, both included;  line 27 contains the function header;  line 28 till 33 contain the function body;  line 32 codes the required return statement; ˆ similarly: MaxOfThree function ˆ the assignment at line 16 calculates a oat by providing some actual parameters (arguments) to the function denit

Use Quizgecko on...
Browser
Browser