1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
//! I'm not familiar with that expression
//!
//!   - **Date:** March 21, 2016
//!   - **Subject:** What it means to be an expression-oriented language, and
//!     how that works out in Rust.
//!   - [**Audio**][mp3]
//!
//! [mp3]: https://www.podtrac.com/pts/redirect.mp3/cdn.newrustacean.com/file/newrustacean/e012.mp3
//!
//! <audio style="width: 100%" title="e012: I'm not familiar with that expression" controls preload=metadata>
//!   <source src="https://www.podtrac.com/pts/redirect.mp3/cdn.newrustacean.com/file/newrustacean/e012.mp3">
//! </audio>
//!
//!
//! Notes
//! -----
//!
//! Rust is an *expression-oriented* language. What does that mean, and how does
//! it play out in Rust? We look at `if` and `match` blocks, discuss looping
//! constructs, and examine functions, and then widen out to discuss how having
//! an expression-oriented language can change the way we think about
//! programming.
//!
//!
//! Links
//! -----
//!
//!   - [Redox][l1]
//!   - [Servo alpha announcement][l2]
//!   - [WebRender][l3]
//!   - [Wired article on Dropbox][l4]
//!   - Rust documentation on expression-oriented-ness:
//!       + [Rust Book][l5]
//!       + [Rust by Example][l6]
//!       + [Rust Reference][l7]
//!   - [Removing Rust ternary][l8]
//!   - [Digits of pi necessary for astronavigation][l9]
//!
//! [l1]: http://www.redox-os.org
//! [l2]: https://groups.google.com/forum/#!topic/mozilla.dev.servo/dcrNW6389g4
//! [l3]: https://air.mozilla.org/bay-area-rust-meetup-february-2016/#@25m50s
//! [l4]: http://www.wired.com/2016/03/epic-story-dropboxs-exodus-amazon-cloud-empire/
//! [l5]: https://doc.rust-lang.org/book/functions.html#expressions-vs-statements
//! [l6]: http://rustbyexample.com/expression.html
//! [l7]: https://doc.rust-lang.org/reference.html#statements-and-expressions
//! [l8]: https://github.com/rust-lang/rust/issues/1698
//! [l9]: http://www.jpl.nasa.gov/edu/news/2016/3/16/how-many-decimals-of-pi-do-we-really-need/
//!
//! Sponsors
//! --------
//!
//!   - Aleksey Pirogov
//!   - Chris Palmer
//!   - [Derek Morr][s3]
//!   - Hamza Sheikh
//!   - Lachlan Collins
//!   - Leif Arne Storset
//!   - Luca Schmid
//!   - Micael Bergeron
//!   - Pascal
//!   - Ralph Giles ("rillian")
//!   - Ralph "FriarTech" Loizzo
//!   - reddraggone9
//!   - Ryan Ollos
//!   - [William Roe][s11]
//!
//! [s3]: https://twitter.com/derekmorr
//! [s11]: http://willroe.me
//!
//! ### Become a sponsor
//!
//!   - <a href="https://www.patreon.com/newrustacean" rel="payment">Patreon</a>
//!   - [Venmo](https://venmo.com/chriskrycho)
//!   - [Dwolla](https://www.dwolla.com/hub/chriskrycho)
//!   - [Cash.me](https://cash.me/$chriskrycho)
//!
//!
//! Contact
//! -------
//!
//!   - New Rustacean:
//!     + Twitter: [@newrustacean](https://www.twitter.com/newrustacean)
//!     + Email: [[email protected]](mailto:[email protected])
//!   - Chris Krycho
//!     + GitHub: [chriskrycho](https://github.com/chriskrycho)
//!     + Twitter: [@chriskrycho](https://www.twitter.com/chriskrycho)

use std::f64;

/// Functions are expressions, and so are their contents.
///
/// This is the foundation of the other items in this modules, because it is in
/// using functions as expressions that we'll be able to demonstrate clearly
/// that if blocks and match blocks are *also* expressions.
///
/// Note that we can see several things going on in the body of this function:
///
/// 1. The items within the function are expressions.
/// 2. The function *returns* the value of the final expression in the function
///    body. But a better way to think about it is to see the function as having
///    that value *itself*, because...
/// 3. The function itself *is* an expression, which is evaluated to have the
///    value of that final expression!
pub fn functions_are_expressions() -> i32 {
    // We can do as many things inside as statements as we like. Note that these
    // statements are actually still expressions, whose value is the empty tuple
    // `()`, sometimes called the "unit type".
    let a = 14;
    let b = 12;

    // Now that we're done, we can just return the desired value by making the
    // final line of the function *just* an expression, not a statement, so that
    // the evaluated value is not `()` but that of the expression (so: 26)!
    a + b
}

/// Like functions, if blocks are expressions.
///
/// This function simple doubly demonstrates this, by showing an assignment from
/// one evaluated expression, and by returning the result of another directly.
pub fn if_blocks_are_expressions() -> f64 {
    // note the terminal boolean expressions, unterminated!
    let a_bool = if "quuxy".len() > 3 {
        print!("{:}", "Totally a long word");
        true
    } else {
        print!("{:}", "Not at all long");
        false
    };

    // This wouldn't work: the compiler would report mismatched types as the
    // values of the `if` and `else` expressions.
    // let mismatched_types = if true {
    //     42
    // } else {
    //     "quuxy"
    // };

    // Here, we are returning the result of this expression, not only from the
    // if/else block, but from the whole function, because *this* expression is
    // the final, unterminated expression of a function, as above!
    if a_bool {
        42.0
    } else {
        f64::consts::PI
    }
}

#[cfg_attr(feature = "clippy", allow(dead_code))]
enum ThreeTypes {
    _First,
    Second,
    _Third,
}

/// Match blocks are also expressions.
///
/// This particular example demonstrates both local binding and returning a
/// match expression's value as the return value from the entire function.
pub fn match_blocks_are_expressions() -> String {
    let a_three_type = ThreeTypes::Second;
    let x = match a_three_type {
        ThreeTypes::_First => 42,
        ThreeTypes::Second => i64::min_value(),
        ThreeTypes::_Third => i64::max_value(),
    };

    match x {
        0...100 => "Less than 100".to_string(),
        _ => "Less than 0, or more than 100".to_string(),
    }
}

/// Block blocks are also expressions!
///
/// In the trivial example below, we have a situation that doesn't come up
/// especially often (and certainly wouldn't in this trivial way), but is a real
/// option and is handy when you need it. You can create arbitrary blocks
pub fn ordinary_blocks_are_expressions() -> i32 {
    let a_block_result = {
        println!("You can evaluate *any* block, see?");
        println!("And the final expression is still returned.");
        // a_block_result will be 14
        14
    };

    // And that's what we'll return from the function, from this utterly
    // pointless block! (These kinds of things aren't always pointless, though.)
    {
        a_block_result
    }
}