-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #41 from botlabs-gg/add-learn
learn: add learning resources
- Loading branch information
Showing
21 changed files
with
1,813 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2020 caubert | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
+++ | ||
title = "Beginner" | ||
weight = 200 | ||
+++ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
+++ | ||
title = "Control Flow 1" | ||
weight = 230 | ||
+++ | ||
|
||
Until now, we have just written some linear code that executes from top to bottom. However, in real-world applications, | ||
we often need to execute different code depending on certain states of our program. This is where _control flow_ comes | ||
into play. | ||
|
||
You already have an intuitive understanding of control flow. For instance, when you cross the street, you look left and | ||
right to see if any cars are coming. If there are no cars, you cross the street. Otherwise ("else"), you wait until the | ||
incoming cars have passed, then check again. This is a simple example of a decision-making process. | ||
|
||
## If Statements | ||
|
||
The most basic form of control flow is the `if` statement. An `if` statement checks a condition and executes a block of | ||
code if the condition is true. If the condition is false, the block of code is skipped. | ||
|
||
```go | ||
{{ if eq 5 5 }} | ||
{{/* It is conventional, though not required, to consistently indent inner blocks of code with spaces or tabs. */}} | ||
Five is equal to five! | ||
{{ end }} | ||
``` | ||
|
||
We use the `eq` comparison function to check whether its given arguments are equal; we will enumerate all comparison | ||
functions in a [later section](#comparison-actions) on this page. | ||
|
||
We can expand this to execute a different block of code if the condition is false by using an `else` block: | ||
|
||
```go | ||
{{ if eq 5 3 }} | ||
Five is equal to three! | ||
{{ else }} | ||
Five is not equal to three! | ||
{{ end }} | ||
``` | ||
|
||
This can be further expanded to check multiple conditions using `else if`, which are checked sequentially until one of | ||
them is true: | ||
|
||
```go | ||
{{ if eq 5 3 }} | ||
Five is equal to three! | ||
{{ else if eq 5 5 }} | ||
Five is equal to five! | ||
{{ else }} | ||
Five is not equal to three or five! | ||
{{ end }} | ||
``` | ||
|
||
{{< callout context="note" title="Note" icon="outline/info-circle" >}} | ||
|
||
The condition of an `if` statement need not be a boolean: in general, an `if` statement will trigger if the condition is | ||
_truthy_: that is, not empty or zero. (Conversely, empty and zero values are _falsy_.) | ||
|
||
For example, consider how you would check whether a string `$s` is empty. One way is to explicitly compare the length of | ||
the string to zero using `if gt (len $s) 0`, but since empty strings are falsy, the more idiomatic solution is to simply | ||
write `if $s`, like so: | ||
|
||
```go | ||
{{ $s := "" }} | ||
{{ if $s }} | ||
not empty | ||
{{ else }} | ||
empty | ||
{{ end }} | ||
``` | ||
|
||
{{< /callout >}} | ||
|
||
#### Guard Clauses | ||
|
||
As your code grows, you may find yourself nesting `if` statements inside each other. This can lead to code that is hard | ||
to read and understand. One way to avoid this is to use _guard clauses_. A guard clause is an `if` statement that checks | ||
for a condition and returns early via the `{{ return }}` action. Therefore, the condition we checked in the earlier | ||
`if`/`else` construct must be negated. | ||
|
||
Rewriting the second example to use these guard clauses yields the following code: | ||
|
||
```go | ||
{{ if ne 5 3 }} | ||
Five is not equal to three! | ||
{{ return }} | ||
{{ end }} | ||
|
||
Five is equal to three! | ||
``` | ||
|
||
Although this example may be a bit contrived, guard clauses can help you avoid deeply nested code and make your code | ||
easier to read, especially when you come back to it at a later date. | ||
|
||
## Comparison Actions | ||
|
||
In programming, we can make decisions by comparing values to each other. We can compare numbers, strings, and other data | ||
types. The result of a comparison is a _boolean_ value, which is either `true` or `false`. Normally, comparisons are | ||
binary operators; however, in custom commands, we use functions to compare values. | ||
|
||
{{< callout context="caution" title="Comparing across Types" icon="outline/alert-triangle" >}} | ||
|
||
Just like you cannot quite compare apples and oranges, you cannot compare values of different types. For instance, you | ||
cannot compare a number to a string. The bot will throw an error if you try to do so, you will have to convert either of | ||
them to the other type first. | ||
|
||
{{< /callout >}} | ||
|
||
We provide the following comparison functions in custom commands: | ||
|
||
- `eq` (equals `==`) | ||
- `ne` (not equals `!=`) | ||
- `lt` (less than `<`) | ||
- `le` (less than or equal to `<=`) | ||
- `gt` (greater than `>`) | ||
- `ge` (greater than or equal to `>=`) | ||
|
||
These functions can only compare basic data types as introduced in [Data Types 1](/learn/beginner/datatypes-1). Strings | ||
are compared on a byte-by-byte basis. Please refer to the [functions documentation](/docs/reference/templates/functions) | ||
for the syntax of these functions. | ||
|
||
## Blocks And Scope | ||
|
||
In [Data Types 1](/learn/beginner/datatypes-1), we introduced the concept of variables. Variables are used to store | ||
values and give them a name. In programming, variables have a _scope_, which defines where in the code the variable can | ||
be accessed. Think of each scope as a "container" for things inside it. | ||
|
||
Often, you will want to have a variable available across multiple scopes. In custom commands, the variable is accessible | ||
in the scope in which it was defined, as well as all nested scopes within. Let us assume that we want to assign a | ||
coolness value, which should be true if the user's name is "alice". We can achieve this by defining a variable in | ||
the outer scope and re-assigning, using the `=` operator, its value in the inner scope: | ||
|
||
```go | ||
{{ $isCool := false }} | ||
|
||
{{ if eq .User.Username "alice" }} | ||
{{ $isCool = true }} | ||
{{ end }} | ||
|
||
Are you cool? {{ $isCool }} | ||
``` | ||
|
||
It is considered good practice to define variables in the smallest scope possible. This makes your code easier to read | ||
and understand, as you do not have to search through the entire codebase to find where a variable was defined. | ||
|
||
{{< callout context="caution" title="Definition and Reassignment" icon="outline/alert-triangle" >}} | ||
|
||
In custom commands, you use `:=` to define a variable, and `=` to reassign a variable. The bot will not throw an error | ||
if you try to re-define a variable using `:=`. Rather, it will define a new variable, effectively overwriting the | ||
existing variable, but only within that scope---the existing variable is untouched in the outer scope. | ||
|
||
{{< /callout >}} | ||
|
||
{{< callout context="danger" title="Unexpected EOF" icon="outline/alert-octagon" >}} | ||
|
||
The following error appears when you are missing an `{{ end }}` action. | ||
|
||
![Responses: template: :XX: unexpected EOF](unexpected-eof.png) | ||
|
||
Each control structure must have a corresponding `{{ end }}` action. If you forget to do so, YAGPDB will not know where | ||
your control structure terminates and hence issues the above error. | ||
|
||
To fix this error, examine each `{{ if ... }}` in your program and verify that each has a matching `{{ end }}`. (The | ||
same applies to other control structures introduced in future chapters, such as `{{ range ... }}`.) | ||
|
||
If you are familiar with C-family programming languages, this error is analogous to forgetting the closing `}` of a | ||
block of code. | ||
|
||
{{< /callout >}} | ||
|
||
## Exercises | ||
|
||
1. Write a Custom Command to determine if the number stored in a variable `$a` is even or odd and print `Number is Even` | ||
or `Number is Odd` depending on the case. Verify the output for the following values of `$a`: 1, 9, 0, 10021, -5. | ||
|
||
2. Predict the output of the following code snippets. If there is an error in the snippet, what is the cause of the | ||
error, and how can it be fixed? Also note down potential improvements to the code that make it easier to follow. | ||
|
||
```go | ||
{{ $num1 := 10 }} | ||
{{ if $num1 }} | ||
{{ num1 := 6 }} | ||
{{ $num1 }} | ||
{{ end }} | ||
{{ if not (mod $num1 3) }} | ||
{{ $num1 }} | ||
{{ end }} | ||
{{ $num1 }} | ||
``` | ||
|
||
```go | ||
{{ $name := "John" }} | ||
{{ if eq $name "John" }} | ||
{{ $familyName := "Walters" }} | ||
{{ end }} | ||
My name is: {{ $name }} {{ $familyName }} | ||
``` | ||
|
||
```go | ||
{{ $mood := "happy" }} | ||
{{ if gt $mood "Sad" }} | ||
Be {{ $mood }}! | ||
{{ else }} | ||
Do not be {{ $mood }}! | ||
{{ end }} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
+++ | ||
title = "Data Types 1" | ||
weight = 220 | ||
+++ | ||
|
||
In this chapter, we will overview how to store data in variables and the basic data types available, which include | ||
[strings](#strings), [numbers](#numbers), and [booleans](#booleans). | ||
|
||
## Variables | ||
|
||
Before we go over data types, we will cover how to store data and refer to it later. We can do this by using variables. | ||
A variable is a way to store a value and give it a name, to which you can refer back to later. | ||
|
||
In Custom Commands, you define a variable by starting with a `$`, its name, and the assignment operator `:=`. To | ||
illustrate this, consider the following example: | ||
|
||
```go | ||
{{ $name := "Alice" }} | ||
{{ $age := 42 }} | ||
{{ $isCool := true }} | ||
|
||
{{ $name }}, aged {{ $age }}, is cool: {{ $isCool }} | ||
``` | ||
|
||
Later on, we may wish to reassign a new value to a variable. We can do this by using the re-assignment operator `=`. | ||
When and why this becomes necessary will be discussed in a later chapter. | ||
|
||
{{< callout context="tip" title="Tip" icon="outline/rocket" >}} | ||
|
||
When debugging your code, you might have to figure out the type of a certain variable. You can do this by using the | ||
[`printf` function](/docs/reference/templates/functions/#string-manipulation) with the `%T` format verb, like so: | ||
|
||
```go | ||
{{ $name := "Alice" }} | ||
{{ printf "%T" $name }} | ||
``` | ||
|
||
{{< /callout >}} | ||
|
||
## Data Types | ||
|
||
If you're completely new to programming, you might not know what a data type is. You can think of a data type as a way | ||
to distinguish between different kinds of things. As a real-life analogy, you can separate food into several categories, | ||
such as fruits, vegetables, and meat. Each category is in that sense its own data type. | ||
|
||
In programming, we have similar categories, such as numbers, strings, and booleans (true / false values). | ||
Each of these categories has its own set of operations that can be performed on them. For instance, you can add two | ||
numbers together, but you cannot add two strings together (at least not in the way you might expect). | ||
|
||
|
||
### Strings | ||
|
||
A string is a sequence of zero or more characters. You can generally think of it as a word or a sentence. | ||
In the bot's template actions, you can create a string by enclosing some text in double quotes (`"`). For instance, | ||
`"Hello, world!"` is a string. We call those *double-quoted strings*. | ||
|
||
Now, here we might run into a problem quite quickly: what if we want to include a double quote in our string? We can't | ||
just write `"Peter said "Hello, world!""`, as the bot would think the string ends at the quotes before `Hello` and not | ||
know that we want them included in the string. To solve this, we must escape the double quote by adding a backslash | ||
(`\`) in front of it. This tells the bot that the double quote is not the end of the string. In other words, | ||
`"Peter said \"Hello, world!\""` would yield the expected result. | ||
|
||
To insert a newline (you would press `Enter` on your keyboard), you can use the escape sequence `\n`. For example the | ||
string `"Hello\nWorld!"` would result in the following output: | ||
|
||
```txt | ||
Hello | ||
World! | ||
``` | ||
|
||
For a full list of escape sequences, you can refer to the [Go documentation](https://golang.org/ref/spec#Rune_literals). | ||
Please note that not all escape sequences are supported by Discord. | ||
|
||
#### Raw String Literals | ||
|
||
It should become relatively clear that a lot of new lines and other special characters can make a quoted string quite | ||
hard to read. To make this easier, you can use backticks (`` ` ``) to create a *raw string literal*. A raw string | ||
literal does not attempt to interpret its contents in any way, and will simply contain the text between the opening `` | ||
` `` and closing `` ` `` unmodified---we cannot even escape a backtick to include one in the string, but we will later | ||
cover functions that solve this special case. | ||
|
||
```txt | ||
`This is my | ||
cool multiline string! | ||
Look at all the new lines!` | ||
``` | ||
|
||
### Numbers | ||
|
||
Numeric values can be represented in two ways, using integers (whole numbers) and floating-point numbers (numbers with a | ||
decimal point). In the bot's template actions, you can create an integer by simply writing a whole number, such as `5`. | ||
For floating-point numbers, you can add a decimal point, like so: `5.0`. | ||
|
||
#### Integers | ||
|
||
In the bot's template actions, integers are represented as 64-bit signed integers. This means that you can store numbers | ||
from `-9223372036854775808` to `9223372036854775807`. If you try to store a number outside this range, the bot will | ||
return an error. | ||
|
||
The bot accepts several notations for integers: | ||
|
||
1. As a base-10 number, such as `42`. This will mean what you think, the number forty-two. | ||
2. As a base-16 number, such as `0x2A`. This is the [hexadecimal representation][hex] of the number forty-two. | ||
3. As a base-8 number, such as `0o52`. This is the [octal representation][oct] of the number forty-two. | ||
4. As a base-2 number, such as `0b101010`. This is the [binary representation][bin] of the number forty-two. | ||
|
||
[hex]: https://en.wikipedia.org/wiki/Hexadecimal | ||
[oct]: https://en.wikipedia.org/wiki/Octal | ||
[bin]: https://en.wikipedia.org/wiki/Binary_number | ||
|
||
#### Floating-Point Numbers | ||
|
||
We represent floating-point numbers as 64-bit IEEE-754 floating-point numbers. This means that you can store numbers | ||
with a precision of about 15 decimal places. If you try to store a number with more precision, the bot will round it to | ||
the nearest representable number. | ||
|
||
There are a lot of ways to define a floating-point number, but the most common way is to use the decimal point, such as | ||
`3.14`. For a full list of ways to define a floating-point number, you can refer to the | ||
[Go documentation](https://golang.org/ref/spec#Floating-point_literals). | ||
|
||
### Booleans | ||
|
||
A boolean is a data type that can only have one of two values: `true` or `false`. Booleans are used to represent the | ||
truth value of an expression. For instance, `5 > 3` would evaluate to `true`, while `5 < 3` would evaluate to `false`. | ||
|
||
You can think of it as a light switch: it can either be on (`true`) or off (`false`). Booleans are often used in | ||
conditional statements, such as `if` statements, to determine which branch of the code should be executed. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.