and, or and a first program's explanation, run¶
Level: 101 · a companion to Functions and Variables
One line: The two-function and/or program that opens chapter 1 of Rust for Machine Learning compiles and prints what the chapter says it will. Three statements in the explanation around it do not hold on rustc 1.98.0, and six more are true but narrower than they read.
fn and(a: bool, b: bool) -> bool {
a && b
}
fn or(a: bool, b: bool) -> bool {
a || b
}
fn main() {
println!("{}", and(true, false)); // false
println!("{}", or(true, false)); // true
}
Where it comes from¶
Rust for Machine Learning by Marcos Silveira, O'Reilly, read as an Early Release (first release 2026-07-23, print listed for August 2027). Chapter 1, "The First Neuron", works toward a perceptron. It first writes the boolean functions AND and OR in Rust, then treats their truth tables as a dataset to learn from. The part checked here is the section "Building Intuition with AND and OR" and the opening of "Replacing Code with Data". An Early Release is the author's unedited draft, so any of this may be fixed before print. The book is listed on the shelf, and the chapter's next section, its first test, is A first test, step by step.
The program in the chapter is the one above, with a and b in variables and a longer format string. Built the way the chapter says, with bare rustc main.rs and then ./main, it prints its two lines exactly. Bare rustc compiles as edition 2015, which makes no difference to a program this small. and and or are ordinary names: neither is a keyword in any edition, unlike in Python and C++ (below).
Three statements that do not hold¶
1. The last expression is returned "explicitly". It is returned implicitly, and rustc uses that word itself. Put a ; after the last line of a function that declares a return type, and the error's label reads implicitly returns () as its body has no tail or return expression. The full transcript is on Functions. return is the explicit form.
2. The short let snippets compile. As printed, three of the four do not: the mut pair, the shadowing pair and the annotated let have no semicolons. The mut pair is introduced as code that will compile, and it stops in the parser:
error: expected `;`, found `a`
--> missing_semicolon.rs:2:21
|
2 | let mut a = true
| ^ help: add `;` here
3 | a = false
| - unexpected token
With the semicolons added, each snippet shows what the text says it does, and Variables covers all three. The one snippet meant to fail, let a = true; followed by a = false;, does fail, with E0384 cannot assign twice to immutable variable.
3. Operators are syntactic sugar for trait method calls. This forward reference sits beside && and ||, the two binary operators it is not true of. They short-circuit, and a method call cannot, because its arguments are evaluated before it runs. There is no trait for them to call:
error[E0432]: unresolved import `std::ops::And`
--> ops_and.rs:1:5
|
1 | use std::ops::And;
| ^^^^^^^^^^---
| |
| no `And` in `ops`
For bool, the single-character operators are the ones that go through traits: & is BitAnd, | is BitOr and ! is Not (block 3 below). Operators are traits lists every operator that is a trait and the few that are not.
The claims, run¶
Verified output of and_or_claims_checked.rs — regenerated by tools/run_examples.py, never hand-typed.
1. The two functions reproduce both truth tables
A B and(A, B) or(A, B)
true true true true
true false false true
false true false true
false false false false
2. and() is not the same as &&: a function gets both arguments already evaluated
noisy(left) && noisy(right):
evaluated left
= false
and(noisy(left), noisy(right)):
evaluated left
evaluated right
= false
3. Operators as trait method calls: true of & | !, not of && ||
true & false = false true.bitand(false) = false
true | false = true true.bitor(false) = true
!true = false true.not() = false
std::ops has no trait for && or || (use std::ops::And is E0432)
4. An immutable binding may be assigned once, not only at the let
let a; then a = true; compiles without mut: a = true
5. Shadowing hides a name; the old value is untouched
first still reads true, the new flag is false
6. A type can come from a later line, not only from the value
before any push: alloc::vec::Vec<bool>
after answers.push(true): [true]
7. A function with no -> returns (), and so does main
nothing_to_return() = ()
8. The ! makes println a macro; the brackets can be any of three kinds
parentheses: true AND false = false
brackets: true OR false = true
braces: false AND false = false
Reading the blocks in order. Blocks 2 and 4 to 8 are the six narrower statements.
- The tables.
andandorreproduce both of the chapter's truth tables, all four rows each. They are the dataset the rest of the chapter learns from. - The two functions only call the operator. They return the same value, but
and(x, y)is a call, and a call evaluates every argument first, left to right.&&stops when the left side isfalse. With literals as arguments you cannot see the difference; with an argument that prints, panics or fetches something, you can. The&trap on Meet theboolis the same thing in operator form. - Operators and traits. Statement 3 above, run: for
bool, the method forms of&,|and!print the same values as the operators. - An immutable variable cannot have its value changed. More precisely, a binding without
mutmay be assigned once.let a;followed bya = true;compiles with nomut, because that assignment is the first. Only a second one isE0384. - The new variable overshadows the value of the old one. Shadowing hides the old name. The old value is untouched: a reference taken before the second
letstill readstrue. A name is not a place and A shadow does not drop take this further. - The type is derived from the value. It can come from a later line instead.
Vec::new()says nothing about the element type, yettype_name_of_valprintsVec<bool>on the line before thepushthat decides it, because inference solves the whole function body at once. Type inference has more cases. maindoesn't return any value. It returns(), like every function with no->— see the unit type. It may also be declared to return aResult.println!prints the value inside its parentheses. What makes it a macro is the!, and the brackets can be(),[]or{}. The first argument is not printed as it stands: it is a format string, and it must be a literal (The braces take a name).
Two more statements hold as written, and rustc enforces both. Function and variable names are snake_case: fn predictOne compiles with a non_snake_case warning suggesting predict_one. Parameters need both a name and a type: fn and(a, b) is a parse error whose message mentions @ and |, because a parameter is a pattern. Both transcripts are on Functions.
If you are coming from another language¶
Python. You could not write this program with these names: and and or are keywords, and def and(a, b): is a SyntaxError on Python 3.14. Python's and and or short-circuit like Rust's, but they return one of their operands, not a bool: 0 and 5 is 0, and [] or "default" is "default". That is what makes x or default a Python idiom. Rust's && and || accept only bool and return only bool. The Rust version of that idiom is a method on Option, such as unwrap_or.
C++. and and or are alternative tokens, spellings of && and || that the language reserves. bool and(bool a, bool b) does not compile. Apple clang 21 stops at the name with expected unqualified-id.
C. Plain C accepts int and(int a, int b), until <iso646.h> is included. That header defines and as a macro for &&, and the same line then fails with expected identifier or '('.
See also¶
- Functions — signatures, the implicit return, argument order, and the transcripts this page links to
- Variables —
let,mut,E0384, and shadowing as a secondlet - Meet the
bool—&&against&, and why neither accepts a number - Operators are traits — the operators that are trait calls, and the ones that are not
- The shadowing map — five pages on what a second
letdoes - Running a scratch program —
rustc main.rswithout Cargo, and its edition-2015 default - What
Cowexplanations get wrong, run — the same kind of check, on a harder topic - A first test, step by step — the same chapter's next section: loading the truth table, test first
- Books — where Rust for Machine Learning sits on the shelf
- What Rust: The Practical Guide says about functions and code blocks, run — the same check on another book's functions section, with its code blocks
Po polsku¶
Rozdział 1 książki Rust for Machine Learning (Marcos Silveira, O'Reilly, wersja Early Release z lipca 2026) zaczyna od dwóch funkcji logicznych, and i or, a potem traktuje ich tablice prawdy (truth tables) jak zbiór danych, z którego uczy się perceptron. Sam program kompiluje się i wypisuje dokładnie to, co obiecuje tekst. and i or są w Ruscie zwykłymi nazwami, bo nie są słowami kluczowymi w żadnej edycji — w Pythonie są, a w C++ to alternatywne zapisy && i ||, więc tam taki program by się nie skompilował.
Trzy zdania z objaśnienia nie wytrzymują sprawdzenia na rustc 1.98.0. Po pierwsze, ostatnie wyrażenie jest zwracane niejawnie (implicitly), a nie jawnie — kompilator sam używa słowa implicitly w komunikacie E0308. Po drugie, krótkie fragmenty z let mut, z przesłanianiem (shadowing) i z adnotacją typu nie mają średników, więc w wydrukowanej postaci się nie kompilują. Po trzecie, zapowiedź, że operatory to „cukier składniowy" na wywołania metod cech (traits), nie dotyczy właśnie && i ||: skracają obliczenia (short-circuit), więc żadna cecha ich nie opisuje, a use std::ops::And to E0432. Przez cechy przechodzą &, | i !.
Sześć kolejnych zdań jest prawdziwych, ale węższych, niż brzmią. Funkcja and(x, y) daje tę samą wartość co x && y, ale oblicza oba argumenty przed wywołaniem. Zmienna bez mut może zostać przypisana raz, niekoniecznie w samym let. Przesłonięcie zabiera nazwę, a nie wartość — referencja wzięta wcześniej dalej widzi starą wartość. Typ może wynikać z późniejszej linii, a nie tylko z wartości. main zwraca (). println! jest makrem przez !, a nie przez nawiasy, które mogą być okrągłe, kwadratowe lub klamrowe. Pierwszy argument nie jest wypisywany wprost, bo jest łańcuchem formatującym i musi być literałem.
Szukaj po polsku: tablica prawdy · skracanie obliczeń logicznych · przesłanianie zmiennych · zwrot niejawny · rust implicitly returns () · rust E0384 cannot assign twice · rust std::ops And