From 6cf0ac93e566366c7496777c6a3c167340bbcda6 Mon Sep 17 00:00:00 2001 From: colinleach Date: Sun, 8 Sep 2024 16:20:06 -0700 Subject: [PATCH 1/6] new concept `booleans` --- concepts/booleans/.meta/config.json | 9 +++ concepts/booleans/about.md | 107 ++++++++++++++++++++++++++++ concepts/booleans/introduction.md | 84 ++++++++++++++++++++++ concepts/booleans/links.json | 6 ++ config.json | 5 ++ 5 files changed, 211 insertions(+) create mode 100644 concepts/booleans/.meta/config.json create mode 100644 concepts/booleans/about.md create mode 100644 concepts/booleans/introduction.md create mode 100644 concepts/booleans/links.json diff --git a/concepts/booleans/.meta/config.json b/concepts/booleans/.meta/config.json new file mode 100644 index 00000000..3d312e12 --- /dev/null +++ b/concepts/booleans/.meta/config.json @@ -0,0 +1,9 @@ +{ + "authors": [ + "colinleach" + ], + "contributors": [ + "SaschaMann" + ], + "blurb": "Julia has boolean values true and false, operators ! (not), && (and), || (or)." +} diff --git a/concepts/booleans/about.md b/concepts/booleans/about.md new file mode 100644 index 00000000..c6b93c8d --- /dev/null +++ b/concepts/booleans/about.md @@ -0,0 +1,107 @@ +# About + +## Booleans in Julia + +True or false values are represented by the `Bool` type. +It contains only two values: `true` and `false`. + +```julia-repl +julia> true +true + +julia> false +false + +julia> typeof(true) +Bool +``` + +## Boolean logic + +Imagine we have the following Boolean expressions in Julia: `5 > x` and `x != 0`. +If `x` was 3 they would both be `true`. +We can express statements like "is x less than 5 and not equal to y?" using [Boolean operators][boolean-operators]: `!` (not), `&&` (and), `||` (or). + +In Julia (and many other programming languages), `&&` has a [higher precedence][operator-precedence] than `||` (in the same way that `*` is applied before `+`). +This means that `true || false && true` evaluates to `true` because it is parsed as `(true || false) && true`. +It is common to include explicit brackets anyway so that the reader doesn't need to think about this. + +### Logical _not_ + +`!` represents the logical "not" operation in Julia. +Not is also called negation. + +```julia-repl +julia> !false +true + +julia> false != true +true + +julia> 3 != "apple" +true + +julia> !(false == true) +true + +julia> !(1 < 7) +false +``` + +### Logical _and_ + +`&&` (two ampersands) represents logical "and" in Julia. + +```julia-repl +julia> 5 > 3 +true + +julia> 1 != 0 +true + +julia> (5 > 3) && (1 != 0) +true +``` + +Parentheses are optional and can make the code easier to read. + +### Logical _or_ + +`||` (two pipe characters) represents logical "or" in Julia. + +```julia-repl +julia> 5 * 5 == 25 +true + +julia> 2 < 1 +false + +julia> (5 * 5 == 25) || (2 < 1) +true +``` + +### Short-circuit evaluation + +When `&&` or `||` are used to link Boolean expressions, Julia evaluates from left to right, and stops when it finds an unambiguous answer. + +Consider this expression: + +```julia-repl +julia> (5 > 12) && (1 != 0) +true +``` + +Because `5 > 12` is `false`, clearly the combined expression must be `false`. +The `1 != 0` expression is not relevant and is never evaluated. + +This is quite often used as a shortcut to trap runtime problems and edge cases, in the form: + +```julia +all_ok || do_something() +``` + +For example, the `do_something` might be an early `return` from the function if `all_ok` is `false`, or assigning a default value to a variable before continuing. + + +[operator-precedence]: https://docs.julialang.org/en/v1/manual/mathematical-operations/#Operator-Precedence-and-Associativity +[boolean-operators]: https://docs.julialang.org/en/ diff --git a/concepts/booleans/introduction.md b/concepts/booleans/introduction.md new file mode 100644 index 00000000..9335fbe3 --- /dev/null +++ b/concepts/booleans/introduction.md @@ -0,0 +1,84 @@ +# Introduction + +## Booleans in Julia + +True or false values are represented by the `Bool` type. +It contains only two values: `true` and `false`. + +```julia-repl +julia> true +true + +julia> false +false + +julia> typeof(true) +Bool +``` + +## Boolean logic + +Imagine we have the following Boolean expressions in Julia: `5 > x` and `x != 0`. +If `x` was 3 they would both be `true`. +We can express statements like "is x less than 5 and not equal to y?" using [Boolean operators][boolean-operators]: `!` (not), `&&` (and), `||` (or). + +In Julia (and many other programming languages), `&&` has a [higher precedence][operator-precedence] than `||` (in the same way that `*` is applied before `+`). +This means that `true || false && true` evaluates to `true` because it is parsed as `(true || false) && true`. +It is common to include explicit brackets anyway so that the reader doesn't need to think about this. + +### Logical _not_ + +`!` represents the logical "not" operation in Julia. +Not is also called negation. + +```julia-repl +julia> !false +true + +julia> false != true +true + +julia> 3 != "apple" +true + +julia> !(false == true) +true + +julia> !(1 < 7) +false +``` + +### Logical _and_ + +`&&` (two ampersands) represents logical "and" in Julia. + +```julia-repl +julia> 5 > 3 +true + +julia> 1 != 0 +true + +julia> (5 > 3) && (1 != 0) +true +``` + +Parentheses are optional and can make the code easier to read. + +### Logical _or_ + +`||` (two pipe characters) represents logical "or" in Julia. + +```julia-repl +julia> 5 * 5 == 25 +true + +julia> 2 < 1 +false + +julia> (5 * 5 == 25) || (2 < 1) +true +``` + +[operator-precedence]: https://docs.julialang.org/en/v1/manual/mathematical-operations/#Operator-Precedence-and-Associativity +[boolean-operators]: https://docs.julialang.org/en/ diff --git a/concepts/booleans/links.json b/concepts/booleans/links.json new file mode 100644 index 00000000..dd267af3 --- /dev/null +++ b/concepts/booleans/links.json @@ -0,0 +1,6 @@ +[ + { + "url": "https://docs.julialang.org/en/v1/manual/mathematical-operations/#Boolean-Operators", + "description": "Boolean Operators, section in the manual" + } +] diff --git a/config.json b/config.json index 8a1bee8d..15eac2c1 100644 --- a/config.json +++ b/config.json @@ -1058,6 +1058,11 @@ "slug": "functions", "name": "Functions" }, + { + "uuid": "813fb2fa-0068-4167-93d6-e8b8e7b7b55c", + "slug": "booleans", + "name": "Booleans" + }, { "uuid": "006ebce8-87cd-4695-87e6-8a7b8dc2f239", "slug": "integer-introduction", From 98d337d5f72c8caa26dc0bc33fba5bf9888d393b Mon Sep 17 00:00:00 2001 From: colinleach Date: Mon, 9 Sep 2024 13:23:47 -0700 Subject: [PATCH 2/6] Update concepts/booleans/about.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: András B Nagy <20251272+BNAndras@users.noreply.github.com> --- concepts/booleans/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/booleans/about.md b/concepts/booleans/about.md index c6b93c8d..1177d185 100644 --- a/concepts/booleans/about.md +++ b/concepts/booleans/about.md @@ -28,7 +28,7 @@ It is common to include explicit brackets anyway so that the reader doesn't need ### Logical _not_ -`!` represents the logical "not" operation in Julia. +`!` represents the logical "not" operation in Julia. Not is also called negation. ```julia-repl From e322b73e9be0127d60dab5aa717c4b9c9868cf3a Mon Sep 17 00:00:00 2001 From: colinleach Date: Mon, 9 Sep 2024 13:23:55 -0700 Subject: [PATCH 3/6] Update concepts/booleans/about.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: András B Nagy <20251272+BNAndras@users.noreply.github.com> --- concepts/booleans/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/booleans/about.md b/concepts/booleans/about.md index 1177d185..07fcf68b 100644 --- a/concepts/booleans/about.md +++ b/concepts/booleans/about.md @@ -24,7 +24,7 @@ We can express statements like "is x less than 5 and not equal to y?" using [Boo In Julia (and many other programming languages), `&&` has a [higher precedence][operator-precedence] than `||` (in the same way that `*` is applied before `+`). This means that `true || false && true` evaluates to `true` because it is parsed as `(true || false) && true`. -It is common to include explicit brackets anyway so that the reader doesn't need to think about this. +It is common to include explicit parentheses anyway so that the reader doesn't need to think about this. ### Logical _not_ From e08b1959f8033ab1ad0d9248fe958e2970f5b9c8 Mon Sep 17 00:00:00 2001 From: colinleach Date: Mon, 9 Sep 2024 16:42:47 -0700 Subject: [PATCH 4/6] Update concepts/booleans/introduction.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: András B Nagy <20251272+BNAndras@users.noreply.github.com> --- concepts/booleans/introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/booleans/introduction.md b/concepts/booleans/introduction.md index 9335fbe3..16ea41b2 100644 --- a/concepts/booleans/introduction.md +++ b/concepts/booleans/introduction.md @@ -23,7 +23,7 @@ If `x` was 3 they would both be `true`. We can express statements like "is x less than 5 and not equal to y?" using [Boolean operators][boolean-operators]: `!` (not), `&&` (and), `||` (or). In Julia (and many other programming languages), `&&` has a [higher precedence][operator-precedence] than `||` (in the same way that `*` is applied before `+`). -This means that `true || false && true` evaluates to `true` because it is parsed as `(true || false) && true`. +This means that `true || false && true` evaluates to `true` because it is parsed as `true || (false && true)`. It is common to include explicit brackets anyway so that the reader doesn't need to think about this. ### Logical _not_ From 31026c37d5145d57682a576c50e599ae5145b343 Mon Sep 17 00:00:00 2001 From: colinleach Date: Tue, 10 Sep 2024 07:49:39 -0700 Subject: [PATCH 5/6] parens --- concepts/booleans/about.md | 2 -- concepts/booleans/introduction.md | 2 -- 2 files changed, 4 deletions(-) diff --git a/concepts/booleans/about.md b/concepts/booleans/about.md index 07fcf68b..47602580 100644 --- a/concepts/booleans/about.md +++ b/concepts/booleans/about.md @@ -63,8 +63,6 @@ julia> (5 > 3) && (1 != 0) true ``` -Parentheses are optional and can make the code easier to read. - ### Logical _or_ `||` (two pipe characters) represents logical "or" in Julia. diff --git a/concepts/booleans/introduction.md b/concepts/booleans/introduction.md index 16ea41b2..a1791106 100644 --- a/concepts/booleans/introduction.md +++ b/concepts/booleans/introduction.md @@ -63,8 +63,6 @@ julia> (5 > 3) && (1 != 0) true ``` -Parentheses are optional and can make the code easier to read. - ### Logical _or_ `||` (two pipe characters) represents logical "or" in Julia. From 202fac979a08ce53038c61855b376e07a52a27c8 Mon Sep 17 00:00:00 2001 From: colinleach Date: Fri, 20 Sep 2024 10:42:23 -0700 Subject: [PATCH 6/6] rewrite of both `about.md` and `introduction.md` --- concepts/booleans/.meta/config.json | 2 +- concepts/booleans/about.md | 107 ++++++++++++++++------------ concepts/booleans/introduction.md | 64 ++++++----------- 3 files changed, 82 insertions(+), 91 deletions(-) diff --git a/concepts/booleans/.meta/config.json b/concepts/booleans/.meta/config.json index 3d312e12..0492fb6e 100644 --- a/concepts/booleans/.meta/config.json +++ b/concepts/booleans/.meta/config.json @@ -3,7 +3,7 @@ "colinleach" ], "contributors": [ - "SaschaMann" + "BNAndras" ], "blurb": "Julia has boolean values true and false, operators ! (not), && (and), || (or)." } diff --git a/concepts/booleans/about.md b/concepts/booleans/about.md index 47602580..30a7bd49 100644 --- a/concepts/booleans/about.md +++ b/concepts/booleans/about.md @@ -16,90 +16,105 @@ julia> typeof(true) Bool ``` -## Boolean logic +In contrast to several other languages, Julia deliberately has no concept of "truthiness". +Only expressions which evaluate to `true` or `false` will be treated as a `Bool`. -Imagine we have the following Boolean expressions in Julia: `5 > x` and `x != 0`. -If `x` was 3 they would both be `true`. -We can express statements like "is x less than 5 and not equal to y?" using [Boolean operators][boolean-operators]: `!` (not), `&&` (and), `||` (or). +Specifically, empty arrays or strings will *not* be interpreted as `false`. +There must be an appropriate test such as `isempty()` if you want special handlind for empty values. -In Julia (and many other programming languages), `&&` has a [higher precedence][operator-precedence] than `||` (in the same way that `*` is applied before `+`). -This means that `true || false && true` evaluates to `true` because it is parsed as `(true || false) && true`. -It is common to include explicit parentheses anyway so that the reader doesn't need to think about this. +## Boolean operators -### Logical _not_ +There are three [Boolean operators][boolean-operators] in Julia. -`!` represents the logical "not" operation in Julia. -Not is also called negation. +`&&` is Boolean "and". +It evaluates to `true` if the expressions on *both* sides of `&&` are `true`. ```julia-repl -julia> !false -true - -julia> false != true -true - -julia> 3 != "apple" -true - -julia> !(false == true) +julia> true && true true -julia> !(1 < 7) +julia> true && false false ``` -### Logical _and_ - -`&&` (two ampersands) represents logical "and" in Julia. +`||` is Boolean "or". +It evaluates to `true` if an expression on *either* side of `||` is `true`. ```julia-repl -julia> 5 > 3 +julia> true || true true -julia> 1 != 0 -true - -julia> (5 > 3) && (1 != 0) +julia> false || true true ``` -### Logical _or_ - -`||` (two pipe characters) represents logical "or" in Julia. +`!` is Boolean "not". +It exchanges (inverts) `true` and `false` values. ```julia-repl -julia> 5 * 5 == 25 -true - -julia> 2 < 1 +julia> !true false -julia> (5 * 5 == 25) || (2 < 1) +julia> !false true ``` -### Short-circuit evaluation +These operators will be familiar to users of many other languages, though *not* Python. + +## Operator precedence + +In more complex expressions, it can be useful to know that `&&` has a slightly higher [precedence][operator-precedence] than `||` *(in the same way that `*` is applied before `+` in arithmetic expressions)*. -When `&&` or `||` are used to link Boolean expressions, Julia evaluates from left to right, and stops when it finds an unambiguous answer. +Relying on this can be confusing and error-prone. +For clarity, use parentheses to make your intention clear. -Consider this expression: +## Short-circuit evaluation + +Does the expression `true || x` depend on the value of `x`, or can the compiler ignore `x`? + +Julia evaluates Boolean expressions from left to right, and stops when it has an unambiguous result. + +For example, `true || x` must be `true`, regardless of `x`, so `x` is not evaluated. +Similarly, `false && y` is `false`, with no need to evaluate `y`. + +Conversely, `true && x` is `true` *only if* `x` is `true`, so `x` must be evaluated. + +Similarly, if we chain multiple operators: ```julia-repl -julia> (5 > 12) && (1 != 0) -true +julia> true && false && something_else +false ``` -Because `5 > 12` is `false`, clearly the combined expression must be `false`. -The `1 != 0` expression is not relevant and is never evaluated. +Because `true && false` must be `false`, the `something_else` is unimportant and is ignored by the compiler. + +In this case, `something_else` did not exist as a variable, but including it in this context gave no error *(test this in the REPL if you doubt it)*. -This is quite often used as a shortcut to trap runtime problems and edge cases, in the form: +Such short-circuit evaluation is quite often used by Julia programmers as a shortcut to trap runtime problems and edge cases: ```julia all_ok || do_something() + +is_problem && do_something_else() ``` For example, the `do_something` might be an early `return` from the function if `all_ok` is `false`, or assigning a default value to a variable before continuing. +This is a slight abuse of Boolean syntax, but it can be very convenient. + +## How Bools work internally + +If a Bool is included in an *arithmetic* expression, `true` is interpreted as `1` and `false` as `0`, reflecting how they are stored. + +If you are used to lower-level languages (C and similar), *please* avoid using this often. +It will reduce code readability and make debugging harder. + +You may sometimes see the numerical values used as a quick way to count how many things are `true`. + +```julia-repl +julia> true + false + true +2 +``` [operator-precedence]: https://docs.julialang.org/en/v1/manual/mathematical-operations/#Operator-Precedence-and-Associativity -[boolean-operators]: https://docs.julialang.org/en/ +[boolean-operators]: https://docs.julialang.org/en/v1/manual/mathematical-operations/#Boolean-Operators diff --git a/concepts/booleans/introduction.md b/concepts/booleans/introduction.md index a1791106..b8818e81 100644 --- a/concepts/booleans/introduction.md +++ b/concepts/booleans/introduction.md @@ -11,72 +11,48 @@ true julia> false false - -julia> typeof(true) -Bool ``` -## Boolean logic - -Imagine we have the following Boolean expressions in Julia: `5 > x` and `x != 0`. -If `x` was 3 they would both be `true`. -We can express statements like "is x less than 5 and not equal to y?" using [Boolean operators][boolean-operators]: `!` (not), `&&` (and), `||` (or). - -In Julia (and many other programming languages), `&&` has a [higher precedence][operator-precedence] than `||` (in the same way that `*` is applied before `+`). -This means that `true || false && true` evaluates to `true` because it is parsed as `true || (false && true)`. -It is common to include explicit brackets anyway so that the reader doesn't need to think about this. +## Boolean Operators -### Logical _not_ +There are three Boolean operators in Julia. -`!` represents the logical "not" operation in Julia. -Not is also called negation. +`&&` is Boolean "and". +It evaluates to `true` if the expressions on *both* sides of `&&` are `true`. ```julia-repl -julia> !false -true - -julia> false != true +julia> true && true true -julia> 3 != "apple" -true - -julia> !(false == true) -true - -julia> !(1 < 7) +julia> true && false false ``` -### Logical _and_ - -`&&` (two ampersands) represents logical "and" in Julia. +`||` is Boolean "or". +It evaluates to `true` if an expression on *either* side of `||` is `true`. ```julia-repl -julia> 5 > 3 +julia> true || true true -julia> 1 != 0 -true - -julia> (5 > 3) && (1 != 0) +julia> false || true true ``` -### Logical _or_ - -`||` (two pipe characters) represents logical "or" in Julia. +`!` is Boolean "not". +It exchanges `true` and `false` values. ```julia-repl -julia> 5 * 5 == 25 -true - -julia> 2 < 1 +julia> !true false -julia> (5 * 5 == 25) || (2 < 1) +julia> !false true ``` -[operator-precedence]: https://docs.julialang.org/en/v1/manual/mathematical-operations/#Operator-Precedence-and-Associativity -[boolean-operators]: https://docs.julialang.org/en/ +For longer and more complicated expressions, it is best to use parentheses to make your intention clear. + +```julia-repl +julia> (true || false) && (false && true) +false +```