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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
//! Once upon a type
//!
//!   - **Date:** March 6, 2016
//!   - **Subject:** Type systems: strong vs. weak, dynamic vs. static, and
//!     degrees of expressivity.
//!   - [**Audio**][mp3]
//!
//! [mp3]: https://www.podtrac.com/pts/redirect.mp3/cdn.newrustacean.com/file/newrustacean/e011.mp3
//!
//! <audio style="width: 100%" title="e011: Once Upon a Type" controls preload=metadata><source src="https://www.podtrac.com/pts/redirect.mp3/cdn.newrustacean.com/file/newrustacean/e011.mp3"></audio>
//!
//!
//! Notes
//! -----
//!
//! Talking about type systems! A broad and wide-ranging discussion about type
//! systems in general, with specific examples from languages like PHP,
//! JavaScript, Python, C, C++, Java, C♯, Haskell, and Rust!
//!
//!   - What is a type system?
//!   - What are the kinds of things we get out of type systems?
//!   - What are the tradeoffs with different type systems?
//!   - What is Rust's type system like?
//!   - What is especially attractive about Rust's type system?
//!
//! A comment on the C integer/character string addition example: what's
//! actually happening there is that the character string is an array "under the
//! covers," and as such has an address. C silently switches to using the memory
//! address, which is of course just an integer, when you try to add the two
//! together. As I said on the show: the result is nonsense (unless you're using
//! this as a way of operating on memory addresses), but it's compileable
//! nonsense. In a stricter and stronger type system, memory addresses and
//! normal numbers shouldn't be addable!
//!
//!
//! Links
//! -----
//!
//!   - [Rust 1.7 released][l1]
//!       + [`HashMap` changes][l2]
//!   - [Introduction to Type Theory][l3]
//!   - [Visualizing Rust's type-system][l4]
//!   - [The Many Kinds of Code Reuse in Rust][l5]
//!
//! [l1]: http://blog.rust-lang.org/2016/03/02/Rust-1.7.html
//! [l2]: http://blog.rust-lang.org/2016/03/02/Rust-1.7.html#library-stabilizations
//! [l3]: http://www.cs.ru.nl/~herman/PUBS/IntroTT-improved.pdf
//! [l4]: https://jadpole.github.io/rust/type-system
//! [l5]: http://cglab.ca/~abeinges/blah/rust-reuse-and-recycle/
//!
//!
//! 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: [hello@newrustacean.com](mailto:hello@newrustacean.com)
//!   - Chris Krycho
//!     + GitHub: [chriskrycho](https://github.com/chriskrycho)
//!     + Twitter: [@chriskrycho](https://www.twitter.com/chriskrycho)

use std::fmt;

/// Is the thing "expressive", whatever that means?
pub enum Expressive {
    Ridiculously,
    PrettyDarn,
    Fairly,
    SortOf,
    Barely,
    NotEvenALittle,
}

impl fmt::Display for Expressive {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let description = match *self {
            Expressive::Ridiculously => "ridiculously",
            Expressive::PrettyDarn => "pretty darn",
            Expressive::Fairly => "fairly",
            Expressive::SortOf => "sort of",
            Expressive::Barely => "barely",
            Expressive::NotEvenALittle => "not even a little",
        };

        write!(f, "{} expressive", description)
    }
}

/// Is the thing *strong*?
pub enum Strong {
    Indeed,
    ABit,
    NotEspecially,
    NopeNopeNope,
}

impl fmt::Display for Strong {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let description = match *self {
            Strong::Indeed => "strong indeed",
            Strong::ABit => "a bit strong",
            Strong::NotEspecially => "not especially strong",
            Strong::NopeNopeNope => "strong? NOPE NOPE NOPE",
        };

        write!(f, "{}", description)
    }
}

/// Is the thing statically known?
pub enum StaticallyKnown {
    Yeah,
    Nope,
}

impl fmt::Display for StaticallyKnown {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let description = match *self {
            StaticallyKnown::Yeah => "it's totally known at compile time",
            StaticallyKnown::Nope => "we don't know anything about it until run time",
        };

        write!(f, "{}", description)
    }
}

/// Look, we composed those enums into another type. How... droll.
pub struct TypeSystem {
    name: String,
    expressive: Expressive,
    strong: Strong,
    statically_known: StaticallyKnown,
}

impl TypeSystem {
    pub fn builder(
        name: &str,
        expressive: Expressive,
        strong: Strong,
        statically_known: StaticallyKnown,
    ) -> TypeSystem {
        TypeSystem {
            name: name.to_string(),
            expressive,
            strong,
            statically_known,
        }
    }
}

/// An incredibly contrived function which just shows enums at work.
///
/// I wanted there to be *some* sample code this episode, you know? This one
/// just assembles the types into a vector and prints them all. It does,
/// however, let us refresh ourselves on a bunch of other concepts we've covered
/// on the show---pretty much everything but generics makes an appearance in
/// some way in this module.
pub fn describe_type_systems() {
    let js = TypeSystem::builder(
        "ECMAScript",
        Expressive::Fairly,
        Strong::NopeNopeNope,
        StaticallyKnown::Nope,
    );

    let php = TypeSystem::builder(
        "PHP",
        Expressive::Barely,
        Strong::NopeNopeNope,
        StaticallyKnown::Nope,
    );

    let c = TypeSystem::builder(
        "C",
        Expressive::Barely,
        Strong::NotEspecially,
        StaticallyKnown::Yeah,
    );

    let cpp = TypeSystem::builder(
        "C++",
        Expressive::SortOf,
        Strong::ABit,
        StaticallyKnown::Yeah,
    );

    let java = TypeSystem::builder(
        "Java",
        Expressive::SortOf,
        Strong::ABit,
        StaticallyKnown::Yeah,
    );

    let csharp = TypeSystem::builder(
        "C♯",
        Expressive::Fairly,
        Strong::Indeed,
        StaticallyKnown::Yeah,
    );

    let swift = TypeSystem::builder(
        "Swift",
        Expressive::PrettyDarn,
        Strong::Indeed,
        StaticallyKnown::Yeah,
    );

    let rust = TypeSystem::builder(
        "Rust",
        Expressive::PrettyDarn,
        Strong::Indeed,
        StaticallyKnown::Yeah,
    );

    let haskell = TypeSystem::builder(
        "Haskell",
        Expressive::Ridiculously,
        Strong::Indeed,
        StaticallyKnown::Yeah,
    );

    let langs = vec![js, php, c, cpp, java, csharp, swift, rust, haskell];
    for lang in langs {
        println!(
            "{language} is {expressive}, {strong}, and {statically_known}",
            language = lang.name,
            expressive = lang.expressive,
            strong = lang.strong,
            statically_known = lang.statically_known
        );
    }
}