Added all files
Getty Ritter
10 years ago
1 | Rust Examples | |
2 | ============= | |
3 | ||
4 | These are small snippets of the Rust, in varying degrees of elaborateness, | |
5 | meant to accompany the presentation given in `presentation/rust.pdf`. I am not | |
6 | a particularly experienced Rust programmer, so these programs may differ | |
7 | significantly from conventional Rust style or idiom, or may be written in | |
8 | a suboptimal way. | |
9 | ||
10 | Right now, the examples include: | |
11 | ||
12 | - An interpreter for the untyped lambda-calculus | |
13 | - A regular-expression matcher | |
14 | ||
15 | Build System | |
16 | ------------ | |
17 | ||
18 | These programs are built using [`redo`](https://github.com/apenwarr/redo), | |
19 | which is my preferred build system for small projects. I understand that not | |
20 | everyone has `redo`, so I've included `do`, which is a small shell | |
21 | implementation of `redo` that rebuilds everything rather than doing clever | |
22 | dependency-tracking like `redo` proper. You can build any of these projects with | |
23 | ||
24 | $ cd project-dir | |
25 | $ ../do | |
26 | ||
27 | and clean any of them with | |
28 | ||
29 | $ cd project-dir | |
30 | $ ../do clean | |
31 | ||
32 | The only project that really _needs_ a build script is the presentation, | |
33 | which gets built with [`pandoc`](http://johnmacfarlane.net/pandoc/) and | |
34 | then compiled with `xelatex`, but each one has a build script in case | |
35 | you want to poke at the commands used to build the projects. |
1 | #!/bin/sh | |
2 | # | |
3 | # A minimal alternative to djb redo that doesn't support incremental builds. | |
4 | # For the full version, visit http://github.com/apenwarr/redo | |
5 | # | |
6 | # The author disclaims copyright to this source file and hereby places it in | |
7 | # the public domain. (2010 12 14) | |
8 | # | |
9 | ||
10 | # By default, no output coloring. | |
11 | green="" | |
12 | bold="" | |
13 | plain="" | |
14 | ||
15 | if [ -n "$TERM" -a "$TERM" != "dumb" ] && tty <&2 >/dev/null 2>&1; then | |
16 | green="$(printf '\033[32m')" | |
17 | bold="$(printf '\033[1m')" | |
18 | plain="$(printf '\033[m')" | |
19 | fi | |
20 | ||
21 | _dirsplit() | |
22 | { | |
23 | base=${1##*/} | |
24 | dir=${1%$base} | |
25 | } | |
26 | ||
27 | dirname() | |
28 | ( | |
29 | _dirsplit "$1" | |
30 | dir=${dir%/} | |
31 | echo "${dir:-.}" | |
32 | ) | |
33 | ||
34 | _dirsplit "$0" | |
35 | export REDO=$(cd "${dir:-.}" && echo "$PWD/$base") | |
36 | ||
37 | DO_TOP= | |
38 | if [ -z "$DO_BUILT" ]; then | |
39 | DO_TOP=1 | |
40 | [ -n "$*" ] || set all # only toplevel redo has a default target | |
41 | export DO_BUILT=$PWD/.do_built | |
42 | : >>"$DO_BUILT" | |
43 | echo "Removing previously built files..." >&2 | |
44 | sort -u "$DO_BUILT" | tee "$DO_BUILT.new" | | |
45 | while read f; do printf "%s\0%s.did\0" "$f" "$f"; done | | |
46 | xargs -0 rm -f 2>/dev/null | |
47 | mv "$DO_BUILT.new" "$DO_BUILT" | |
48 | DO_PATH=$DO_BUILT.dir | |
49 | export PATH=$DO_PATH:$PATH | |
50 | rm -rf "$DO_PATH" | |
51 | mkdir "$DO_PATH" | |
52 | for d in redo redo-ifchange; do | |
53 | ln -s "$REDO" "$DO_PATH/$d"; | |
54 | done | |
55 | [ -e /bin/true ] && TRUE=/bin/true || TRUE=/usr/bin/true | |
56 | for d in redo-ifcreate redo-stamp redo-always; do | |
57 | ln -s $TRUE "$DO_PATH/$d"; | |
58 | done | |
59 | fi | |
60 | ||
61 | ||
62 | _find_dofile_pwd() | |
63 | { | |
64 | dofile=default.$1.do | |
65 | while :; do | |
66 | dofile=default.${dofile#default.*.} | |
67 | [ -e "$dofile" -o "$dofile" = default.do ] && break | |
68 | done | |
69 | ext=${dofile#default} | |
70 | ext=${ext%.do} | |
71 | base=${1%$ext} | |
72 | } | |
73 | ||
74 | ||
75 | _find_dofile() | |
76 | { | |
77 | local prefix= | |
78 | while :; do | |
79 | _find_dofile_pwd "$1" | |
80 | [ -e "$dofile" ] && break | |
81 | [ "$PWD" = "/" ] && break | |
82 | target=${PWD##*/}/$target | |
83 | tmp=${PWD##*/}/$tmp | |
84 | prefix=${PWD##*/}/$prefix | |
85 | cd .. | |
86 | done | |
87 | base=$prefix$base | |
88 | } | |
89 | ||
90 | ||
91 | _run_dofile() | |
92 | { | |
93 | export DO_DEPTH="$DO_DEPTH " | |
94 | export REDO_TARGET=$PWD/$target | |
95 | local line1 | |
96 | set -e | |
97 | read line1 <"$PWD/$dofile" || true | |
98 | cmd=${line1#"#!/"} | |
99 | if [ "$cmd" != "$line1" ]; then | |
100 | /$cmd "$PWD/$dofile" "$@" >"$tmp.tmp2" | |
101 | else | |
102 | :; . "$PWD/$dofile" >"$tmp.tmp2" | |
103 | fi | |
104 | } | |
105 | ||
106 | ||
107 | _do() | |
108 | { | |
109 | local dir=$1 target=$2 tmp=$3 | |
110 | if [ ! -e "$target" ] || [ -d "$target" -a ! -e "$target.did" ]; then | |
111 | printf '%sdo %s%s%s%s\n' \ | |
112 | "$green" "$DO_DEPTH" "$bold" "$dir$target" "$plain" >&2 | |
113 | echo "$PWD/$target" >>"$DO_BUILT" | |
114 | dofile=$target.do | |
115 | base=$target | |
116 | ext= | |
117 | [ -e "$target.do" ] || _find_dofile "$target" | |
118 | if [ ! -e "$dofile" ]; then | |
119 | echo "do: $target: no .do file" >&2 | |
120 | return 1 | |
121 | fi | |
122 | [ ! -e "$DO_BUILT" ] || [ ! -d "$(dirname "$target")" ] || | |
123 | : >>"$target.did" | |
124 | ( _run_dofile "$target" "$base" "$tmp.tmp" ) | |
125 | rv=$? | |
126 | if [ $rv != 0 ]; then | |
127 | printf "do: %s%s\n" "$DO_DEPTH" \ | |
128 | "$dir$target: got exit code $rv" >&2 | |
129 | rm -f "$tmp.tmp" "$tmp.tmp2" | |
130 | return $rv | |
131 | fi | |
132 | mv "$tmp.tmp" "$target" 2>/dev/null || | |
133 | ! test -s "$tmp.tmp2" || | |
134 | mv "$tmp.tmp2" "$target" 2>/dev/null | |
135 | rm -f "$tmp.tmp2" | |
136 | else | |
137 | echo "do $DO_DEPTH$target exists." >&2 | |
138 | fi | |
139 | } | |
140 | ||
141 | ||
142 | # Make corrections for directories that don't actually exist yet. | |
143 | _dir_shovel() | |
144 | { | |
145 | local dir base | |
146 | xdir=$1 xbase=$2 xbasetmp=$2 | |
147 | while [ ! -d "$xdir" -a -n "$xdir" ]; do | |
148 | _dirsplit "${xdir%/}" | |
149 | xbasetmp=${base}__$xbase | |
150 | xdir=$dir xbase=$base/$xbase | |
151 | echo "xbasetmp='$xbasetmp'" >&2 | |
152 | done | |
153 | } | |
154 | ||
155 | ||
156 | _redo() | |
157 | { | |
158 | set +e | |
159 | for i in "$@"; do | |
160 | _dirsplit "$i" | |
161 | _dir_shovel "$dir" "$base" | |
162 | dir=$xdir base=$xbase basetmp=$xbasetmp | |
163 | ( cd "$dir" && _do "$dir" "$base" "$basetmp" ) | |
164 | [ "$?" = 0 ] || return 1 | |
165 | done | |
166 | } | |
167 | ||
168 | ||
169 | _redo "$@" | |
170 | [ "$?" = 0 ] || exit 1 | |
171 | ||
172 | if [ -n "$DO_TOP" ]; then | |
173 | echo "Removing stamp files..." >&2 | |
174 | [ ! -e "$DO_BUILT" ] || | |
175 | while read f; do printf "%s.did\0" "$f"; done <"$DO_BUILT" | | |
176 | xargs -0 rm -f 2>/dev/null | |
177 | fi |
1 | if [ -e lcalc ]; then rm lcalc; fi |
1 | redo-ifchange lcalc |
1 | use std::str::eq_slice; | |
2 | ||
3 | #[deriving(Eq,Clone)] | |
4 | enum Term { | |
5 | Num(int), | |
6 | Var(~str), | |
7 | Lam(~str, ~Term), | |
8 | App(~Term, ~Term), | |
9 | Let(~str, ~Term, ~Term), | |
10 | } | |
11 | ||
12 | #[deriving(Eq,Clone)] | |
13 | enum Val { | |
14 | VNum(int), | |
15 | VLam(~str, ~Term, ~Env), | |
16 | } | |
17 | ||
18 | #[deriving(Eq,Clone)] | |
19 | enum Env { | |
20 | Empty, | |
21 | Binding(~str, ~Val, ~Env), | |
22 | } | |
23 | ||
24 | fn lookup(s: &str, e: &Env) -> ~Val { | |
25 | match *e { | |
26 | Empty => { fail!(format!("Couldn't find {} in environment", s)) } | |
27 | Binding(ref n, ref v, ref p) => { | |
28 | if eq_slice(*n, s) { | |
29 | v.clone() | |
30 | } else { | |
31 | lookup(s, *p) | |
32 | } | |
33 | } | |
34 | } | |
35 | } | |
36 | ||
37 | fn eval(t: &Term, e: &Env) -> ~Val { | |
38 | match t { | |
39 | &Num(num) => { ~VNum(num) } | |
40 | &Var(ref str) => { lookup(*str, e) } | |
41 | &Lam(ref s, ref b) => { ~VLam(s.clone(), b.clone(), ~e.clone()) } | |
42 | &App(ref f, ref x) => { | |
43 | match (*eval(*f, e)) { | |
44 | VLam(ref arg, ref body, ref env) => { | |
45 | let newEnv = Binding(arg.clone(), | |
46 | eval(*x, e), | |
47 | env.clone()); | |
48 | eval(*body, &newEnv) | |
49 | } | |
50 | _ => fail!() | |
51 | } | |
52 | } | |
53 | &Let(ref s, ref t, ref b) => { | |
54 | let newEnv = Binding(s.clone(), | |
55 | eval(*t, e), | |
56 | ~e.clone()); | |
57 | eval(*b, &newEnv) | |
58 | } | |
59 | } | |
60 | } | |
61 | ||
62 | fn main() { | |
63 | // (λx.λy.x)(5)(6) | |
64 | let s1 = ~App(~App(~Lam(~"x",~Lam(~"y", ~Var(~"x"))),~Num(5)),~Num(8)); | |
65 | // let f = (λx.λy.x)(2) in f 4 | |
66 | let s2 = ~Let( ~"f", | |
67 | ~App(~Lam(~"x",~Lam(~"y", ~Var(~"x"))),~Num(2)), | |
68 | ~App(~Var(~"f"),~Num(4)) | |
69 | ); | |
70 | let e = Empty; | |
71 | println!("s1: {:?}", eval(s1, &e)); | |
72 | println!("s2: {:?}", eval(s2, &e)); | |
73 | } |
1 | redo-ifchange rust.pdf |
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
1 | <?xml version="1.0" encoding="ISO-8859-1"?> | |
2 | <!-- Generator: Adobe Illustrator 15.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> | |
3 | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | |
4 | <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="144px" height="144px" viewBox="19 19 106 106" style="enable-background:new 0 0 144 144;" xml:space="preserve"> | |
5 | <path d="M122.631,69.716l-4.394-2.72c-0.037-0.428-0.079-0.855-0.125-1.28l3.776-3.522c0.384-0.358,0.556-0.888,0.452-1.401 c-0.101-0.515-0.462-0.939-0.953-1.122l-4.827-1.805c-0.121-0.418-0.248-0.833-0.378-1.246l3.011-4.182 c0.307-0.425,0.37-0.978,0.17-1.463c-0.2-0.483-0.637-0.829-1.154-0.914l-5.09-0.828c-0.198-0.386-0.404-0.766-0.612-1.143 l2.139-4.695c0.219-0.478,0.174-1.034-0.118-1.468c-0.291-0.436-0.784-0.691-1.31-0.671l-5.166,0.18 c-0.267-0.334-0.539-0.665-0.816-0.99l1.187-5.032c0.12-0.511-0.031-1.046-0.403-1.417c-0.369-0.37-0.905-0.523-1.416-0.403 l-5.031,1.186c-0.326-0.276-0.657-0.549-0.992-0.816l0.181-5.166c0.02-0.523-0.235-1.02-0.671-1.31 c-0.437-0.292-0.99-0.336-1.467-0.119l-4.694,2.14c-0.379-0.208-0.759-0.414-1.143-0.613l-0.83-5.091 c-0.084-0.516-0.43-0.954-0.914-1.154c-0.483-0.201-1.037-0.136-1.462,0.17l-4.185,3.011c-0.412-0.131-0.826-0.257-1.244-0.377 l-1.805-4.828c-0.183-0.492-0.607-0.853-1.122-0.955c-0.514-0.101-1.043,0.07-1.4,0.452l-3.522,3.779 c-0.425-0.047-0.853-0.09-1.28-0.125l-2.72-4.395c-0.275-0.445-0.762-0.716-1.286-0.716s-1.011,0.271-1.285,0.716l-2.72,4.395 c-0.428,0.035-0.856,0.078-1.281,0.125l-3.523-3.779c-0.357-0.382-0.887-0.553-1.4-0.452c-0.515,0.103-0.939,0.463-1.122,0.955 l-1.805,4.828c-0.418,0.12-0.832,0.247-1.245,0.377l-4.184-3.011c-0.425-0.307-0.979-0.372-1.463-0.17 c-0.483,0.2-0.83,0.638-0.914,1.154l-0.83,5.091c-0.384,0.199-0.764,0.404-1.143,0.613l-4.694-2.14 c-0.477-0.218-1.033-0.173-1.467,0.119c-0.436,0.29-0.691,0.787-0.671,1.31l0.18,5.166c-0.334,0.267-0.665,0.54-0.992,0.816 l-5.031-1.186c-0.511-0.119-1.047,0.033-1.417,0.403c-0.372,0.371-0.523,0.906-0.403,1.417l1.185,5.032 c-0.275,0.326-0.547,0.656-0.814,0.99l-5.166-0.18c-0.521-0.015-1.019,0.235-1.31,0.671c-0.292,0.434-0.336,0.99-0.119,1.468 l2.14,4.695c-0.208,0.377-0.414,0.757-0.613,1.143l-5.09,0.828c-0.517,0.084-0.953,0.43-1.154,0.914 c-0.2,0.485-0.135,1.038,0.17,1.463l3.011,4.182c-0.131,0.413-0.258,0.828-0.378,1.246l-4.828,1.805 c-0.49,0.183-0.851,0.607-0.953,1.122c-0.102,0.514,0.069,1.043,0.452,1.401l3.777,3.522c-0.047,0.425-0.089,0.853-0.125,1.28 l-4.394,2.72c-0.445,0.275-0.716,0.761-0.716,1.286s0.271,1.011,0.716,1.285l4.394,2.72c0.036,0.428,0.078,0.855,0.125,1.28 l-3.777,3.523c-0.383,0.357-0.554,0.887-0.452,1.4c0.102,0.515,0.463,0.938,0.953,1.122l4.828,1.805 c0.12,0.418,0.247,0.833,0.378,1.246l-3.011,4.183c-0.306,0.426-0.371,0.979-0.17,1.462c0.201,0.485,0.638,0.831,1.155,0.914 l5.089,0.828c0.199,0.386,0.403,0.766,0.613,1.145l-2.14,4.693c-0.218,0.477-0.173,1.032,0.119,1.468 c0.292,0.437,0.789,0.692,1.31,0.671l5.164-0.181c0.269,0.336,0.54,0.665,0.816,0.992l-1.185,5.033 c-0.12,0.51,0.031,1.043,0.403,1.414c0.369,0.373,0.906,0.522,1.417,0.402l5.031-1.185c0.327,0.278,0.658,0.548,0.992,0.814 l-0.18,5.167c-0.02,0.523,0.235,1.019,0.671,1.311c0.434,0.291,0.99,0.335,1.467,0.117l4.694-2.139 c0.378,0.21,0.758,0.414,1.143,0.613l0.83,5.088c0.084,0.518,0.43,0.956,0.914,1.155c0.483,0.201,1.038,0.136,1.463-0.169 l4.182-3.013c0.413,0.131,0.828,0.259,1.246,0.379l1.805,4.826c0.183,0.49,0.607,0.853,1.122,0.953 c0.514,0.104,1.043-0.068,1.4-0.452l3.523-3.777c0.425,0.049,0.853,0.09,1.281,0.128l2.72,4.394 c0.274,0.443,0.761,0.716,1.285,0.716s1.011-0.272,1.286-0.716l2.72-4.394c0.428-0.038,0.855-0.079,1.28-0.128l3.522,3.777 c0.357,0.384,0.887,0.556,1.4,0.452c0.515-0.101,0.939-0.463,1.122-0.953l1.805-4.826c0.418-0.12,0.833-0.248,1.246-0.379 l4.183,3.013c0.425,0.305,0.979,0.37,1.462,0.169c0.484-0.199,0.83-0.638,0.914-1.155l0.83-5.088 c0.384-0.199,0.764-0.406,1.143-0.613l4.694,2.139c0.477,0.218,1.032,0.174,1.467-0.117c0.436-0.292,0.69-0.787,0.671-1.311 l-0.18-5.167c0.334-0.267,0.665-0.536,0.991-0.814l5.031,1.185c0.511,0.12,1.047-0.029,1.416-0.402 c0.372-0.371,0.523-0.904,0.403-1.414l-1.185-5.033c0.276-0.327,0.548-0.656,0.814-0.992l5.166,0.181 c0.521,0.021,1.019-0.234,1.31-0.671c0.292-0.436,0.337-0.991,0.118-1.468l-2.139-4.693c0.209-0.379,0.414-0.759,0.612-1.145 l5.09-0.828c0.518-0.083,0.954-0.429,1.154-0.914c0.2-0.483,0.137-1.036-0.17-1.462l-3.011-4.183 c0.13-0.413,0.257-0.828,0.378-1.246l4.827-1.805c0.491-0.184,0.853-0.607,0.953-1.122c0.104-0.514-0.068-1.043-0.452-1.4 l-3.776-3.523c0.046-0.425,0.088-0.853,0.125-1.28l4.394-2.72c0.445-0.274,0.716-0.761,0.716-1.285S123.076,69.991,122.631,69.716z M93.222,106.167c-1.678-0.362-2.745-2.016-2.385-3.699c0.359-1.681,2.012-2.751,3.689-2.389c1.678,0.359,2.747,2.016,2.387,3.696 S94.899,106.526,93.222,106.167z M91.729,96.069c-1.531-0.328-3.037,0.646-3.365,2.18l-1.56,7.28 c-4.814,2.185-10.16,3.399-15.79,3.399c-5.759,0-11.221-1.274-16.121-3.552l-1.559-7.28c-0.328-1.532-1.834-2.508-3.364-2.179 l-6.427,1.38c-1.193-1.228-2.303-2.536-3.323-3.917h31.272c0.354,0,0.59-0.064,0.59-0.386V81.932c0-0.322-0.236-0.386-0.59-0.386 h-9.146v-7.012h9.892c0.903,0,4.828,0.258,6.083,5.275c0.393,1.543,1.256,6.562,1.846,8.169c0.588,1.802,2.982,5.402,5.533,5.402 h15.583c0.177,0,0.366-0.02,0.565-0.056c-1.081,1.469-2.267,2.859-3.544,4.158L91.729,96.069z M48.477,106.015 c-1.678,0.362-3.33-0.708-3.691-2.389c-0.359-1.684,0.708-3.337,2.386-3.699c1.678-0.359,3.331,0.711,3.691,2.392 C51.222,103.999,50.154,105.655,48.477,106.015z M36.614,57.91c0.696,1.571-0.012,3.412-1.581,4.107 c-1.569,0.697-3.405-0.012-4.101-1.584c-0.696-1.572,0.012-3.41,1.581-4.107C34.083,55.63,35.918,56.338,36.614,57.91z M32.968,66.553l6.695-2.975c1.43-0.635,2.076-2.311,1.441-3.744l-1.379-3.118h5.423V81.16H34.207 c-0.949-3.336-1.458-6.857-1.458-10.496C32.749,69.275,32.824,67.902,32.968,66.553z M62.348,64.179v-7.205h12.914 c0.667,0,4.71,0.771,4.71,3.794c0,2.51-3.101,3.41-5.651,3.41H62.348z M109.28,70.664c0,0.956-0.035,1.902-0.105,2.841h-3.926 c-0.393,0-0.551,0.258-0.551,0.643v1.803c0,4.244-2.393,5.167-4.49,5.402c-1.997,0.225-4.211-0.836-4.484-2.058 c-1.178-6.626-3.141-8.041-6.241-10.486c3.847-2.443,7.85-6.047,7.85-10.871c0-5.209-3.571-8.49-6.005-10.099 c-3.415-2.251-7.196-2.702-8.216-2.702H42.509c5.506-6.145,12.968-10.498,21.408-12.082l4.786,5.021 c1.082,1.133,2.874,1.175,4.006,0.092l5.355-5.122c11.221,2.089,20.721,9.074,26.196,18.657l-3.666,8.28 c-0.633,1.433,0.013,3.109,1.442,3.744l7.058,3.135C109.216,68.115,109.28,69.381,109.28,70.664z M68.705,28.784 c1.24-1.188,3.207-1.141,4.394,0.101c1.185,1.245,1.14,3.214-0.103,4.401c-1.24,1.188-3.207,1.142-4.394-0.102 C67.418,31.941,67.463,29.972,68.705,28.784z M105.085,58.061c0.695-1.571,2.531-2.28,4.1-1.583 c1.569,0.696,2.277,2.536,1.581,4.107c-0.695,1.572-2.531,2.281-4.101,1.584C105.098,61.473,104.39,59.634,105.085,58.061z"/> | |
6 | </svg>⏎ |
1 | % The Rust Programming Language | |
2 | % G.D. Ritter | |
3 | % March 2014 | |
4 | ||
5 | # The Rust Programming Language | |
6 | ||
7 | ![](imgs/rust-logo.png) | |
8 | ||
9 | A new systems programming language being developed by Mozilla Research, with | |
10 | an emphasis on correctness while still allowing for very low-level programing | |
11 | by emphasizing _zero-cost abstractions_. | |
12 | ||
13 | # Low-Level Programming | |
14 | ||
15 | # Low-Level Programming | |
16 | ||
17 | \begin{center} | |
18 | \includegraphics[width=.9\textwidth]{imgs/kanye-water-bottle-01.png} | |
19 | \end{center} | |
20 | ||
21 | # Low-Level Programming | |
22 | ||
23 | \begin{center} | |
24 | \includegraphics[width=.9\textwidth]{imgs/kanye-water-bottle-02.png} | |
25 | \end{center} | |
26 | ||
27 | # Systems Programming Languages | |
28 | ||
29 | > System software is computer software designed to operate and control the | |
30 | > computer hardware and to provide a platform for running application | |
31 | > software, and includes such things as operating systems, utility software, | |
32 | > device drivers, compilers, and linkers. | |
33 | > | |
34 | > —Wikipedia | |
35 | ||
36 | > "Systems programs" means "programs where the constant factors are important". | |
37 | > | |
38 | > —Comment by `neelk` on Lambda the Ultimate | |
39 | ||
40 | # Systems Programming Languages | |
41 | ||
42 | ## Example Program | |
43 | ||
44 | ~~~~{.haskell} | |
45 | data Point = { x, y : Int } | |
46 | ||
47 | addPoint : Point -> Point -> Point | |
48 | addPoint p1 p2 = { x = p1.x + p2.x, y = p1.y + p2.y } | |
49 | ||
50 | main : () | |
51 | main = { let a = { x = 1, y = 2 } | |
52 | ; let b = malloc { x = 4, y = 3} | |
53 | ; print (addPoint a (deref b)) | |
54 | ; free(b) | |
55 | } | |
56 | ~~~~ | |
57 | ||
58 | # Systems Programming Languages | |
59 | ||
60 | ## C | |
61 | ||
62 | ~~~~{.c} | |
63 | typedef struct { int x, y; } point; | |
64 | ||
65 | point add(point a, point b) { | |
66 | point result = { a.x + b.x, a.y + b.y }; | |
67 | return result; | |
68 | } | |
69 | ||
70 | void main(int argc, char* argv[]) { | |
71 | point a = { 1, 2 }; | |
72 | point* b = malloc(sizeof(point)); | |
73 | b->x = 4; b->y = 3; | |
74 | point c = add(a, *b); | |
75 | printf("{.x = %d, .y = %d}\n", c.x, c.y); | |
76 | free(b); | |
77 | } | |
78 | ~~~~ | |
79 | ||
80 | # Systems Programming Languages | |
81 | ||
82 | ## C++ | |
83 | ||
84 | ~~~~{.cpp} | |
85 | struct point { | |
86 | int x, y; | |
87 | point(int _x, int _y) { x = _x; y = _y; } | |
88 | point add(point other) { | |
89 | return point(x + other.x, y + other.y); | |
90 | } | |
91 | }; | |
92 | int main(int argc, char* argv[]) { | |
93 | point a(1, 2); | |
94 | point* b = new point(4, 3); | |
95 | point c = a.add(*b); | |
96 | std::cout << "{ .x = " << c.x; | |
97 | std::cout << ", .y = " << c.y << " }" << std::endl; | |
98 | delete b; | |
99 | } | |
100 | ~~~~ | |
101 | ||
102 | # Systems Programming Languages | |
103 | ||
104 | ## Go | |
105 | ||
106 | ~~~~{.go} | |
107 | type Point struct { X, Y int } | |
108 | ||
109 | func (a Point) add(b Point) Point { | |
110 | return Point{ a.X + b.X, a.Y + b.Y } | |
111 | } | |
112 | ||
113 | func main() { | |
114 | a := Point{1, 2} | |
115 | b := new(Point) | |
116 | b.X, b.Y = 4, 3 | |
117 | fmt.Println(a.add(*b)) | |
118 | // No free, because Go is garbage-collected | |
119 | } | |
120 | ~~~~ | |
121 | ||
122 | # Systems Programming Languages | |
123 | ||
124 | ## D | |
125 | ||
126 | ~~~~{.d} | |
127 | struct Point { | |
128 | int x, y; | |
129 | Point add(Point other) { | |
130 | return Point(this.x + other.x, this.y + other.y); | |
131 | } | |
132 | } | |
133 | ||
134 | void main() { | |
135 | Point a = Point(1, 2); | |
136 | Point* b = cast(Point*)GC.malloc(Point.sizeof); | |
137 | b.x = 4; b.y = 3; | |
138 | writeln(a.add(*b)); | |
139 | GC.free(b); | |
140 | } | |
141 | ~~~~ | |
142 | ||
143 | # Systems Programming Languages | |
144 | ||
145 | ## Nimrod | |
146 | ||
147 | ~~~~ | |
148 | type Point = tuple[x: int, y: int] | |
149 | ||
150 | proc add(a: Point, b: Point): Point = | |
151 | (x: a.x + b.x, y: a.y + b.y) | |
152 | ||
153 | var a : Point | |
154 | var b : ptr Point | |
155 | ||
156 | a = (x: 1, y: 2) | |
157 | b = cast[ptr Point](alloc(sizeof(Point))) | |
158 | b.x = 4 | |
159 | b.y = 3 | |
160 | echo(add(a, b[])) | |
161 | dealloc(b) | |
162 | ~~~~ | |
163 | ||
164 | # Systems Programming Languages | |
165 | ||
166 | ## Rust | |
167 | ||
168 | ~~~~{.rust} | |
169 | struct Point { x: int, y: int } | |
170 | ||
171 | impl Point { | |
172 | fn add(self, other: Point) -> Point { | |
173 | Point { x: self.x + other.x, | |
174 | y: self.y + other.y } | |
175 | } | |
176 | } | |
177 | ||
178 | fn main() { | |
179 | let a = Point { x: 1, y: 2 }; | |
180 | let b = ~Point { x: 4, y: 3 }; | |
181 | println!("{:?}", a.add(*b)); | |
182 | } | |
183 | ~~~~ | |
184 | ||
185 | # Basics of Rust | |
186 | ||
187 | # Basics of Rust | |
188 | ||
189 | > It's like C++ grew up, went to grad school, started dating Haskell, and | |
190 | > is sharing an office with Erlang... | |
191 | > | |
192 | > —Michael Sullivan | |
193 | ||
194 | # Basics of Rust | |
195 | ||
196 | ## Recursive Factorial | |
197 | ||
198 | ~~~~{.rust} | |
199 | fn fact1(n: int) -> int { | |
200 | if n <= 0 { | |
201 | 1 | |
202 | } else { | |
203 | n * fact1(n-1) | |
204 | } | |
205 | } | |
206 | ~~~~ | |
207 | ||
208 | ## Another Recursive Factorial | |
209 | ||
210 | ~~~~{.rust} | |
211 | fn fact2(n: int) -> int { | |
212 | match n { | |
213 | 0 => { 1 } | |
214 | _ => { n * fact2(n-1) } | |
215 | } | |
216 | } | |
217 | ~~~~ | |
218 | ||
219 | # Basics of Rust | |
220 | ||
221 | ## An Imperative Factorial | |
222 | ||
223 | ~~~~{.rust} | |
224 | fn fact3(mut n: int) -> int { | |
225 | let mut res = 1; | |
226 | while (n > 0) { | |
227 | res *= n; | |
228 | n -= 1; | |
229 | } | |
230 | res | |
231 | } | |
232 | ~~~~ | |
233 | ||
234 | ## One More Imperative Factorial | |
235 | ||
236 | ~~~~{.rust} | |
237 | fn fact4(mut n: int) -> int { | |
238 | for i in range(1, n) { n *= i; } | |
239 | return n; | |
240 | } | |
241 | ~~~~ | |
242 | ||
243 | # Basics of Rust | |
244 | ||
245 | ## Tuples | |
246 | ||
247 | ~~~~{.rust} | |
248 | { | |
249 | let t: (int, int, int) = (1,2,3); | |
250 | let (a,b,c) = t; | |
251 | let r = match t { (a,b,c) => a + b + c }; | |
252 | } | |
253 | ~~~~ | |
254 | ||
255 | ## Tuple Structs (i.e. named tuples) | |
256 | ||
257 | ~~~~{.rust} | |
258 | struct T(bool, int); | |
259 | fn f(t: T) -> int { | |
260 | let T(myBool, myInt) = t; | |
261 | return if myBool { myInt } else { -myInt }; | |
262 | } | |
263 | ~~~~ | |
264 | ||
265 | # Basics of Rust | |
266 | ||
267 | ## Structs | |
268 | ||
269 | ~~~~{.rust} | |
270 | struct Point { x: f64, y: f64 } | |
271 | ||
272 | fn isOrigin1 (p: Point) -> bool { | |
273 | p.x == 0.0 && p.y == 0.0 | |
274 | } | |
275 | ~~~~ | |
276 | ||
277 | ~~~~{.rust} | |
278 | fn isOrigin2 (p: Point) -> bool { | |
279 | match p { | |
280 | Point { x: 0.0, y: 0.0 } => true, | |
281 | _ => false | |
282 | } | |
283 | } | |
284 | ~~~~ | |
285 | ||
286 | # Basics of Rust | |
287 | ||
288 | ## Enums | |
289 | ||
290 | ~~~~{.rust} | |
291 | enum Color { Red, Green, Blue } | |
292 | ||
293 | enum Shape { | |
294 | Circle(Point, f64), | |
295 | Rectangle(Point, Point), | |
296 | } | |
297 | ||
298 | fn area(s: Shape) -> f64 { | |
299 | match s { | |
300 | Circle(_, sz) => f64::consts::pi * sz * sz, | |
301 | Rectangle(p1, p2) => (p2.x - p1.x) * (p2.y - p1.y) | |
302 | } | |
303 | } | |
304 | ~~~~ | |
305 | ||
306 | # Pointers and Memory | |
307 | ||
308 | # Pointers and Memory | |
309 | ||
310 | \begin{center} | |
311 | \includegraphics[width=.9\textwidth]{imgs/dawkins-owned.png} | |
312 | \end{center} | |
313 | ||
314 | # Pointers and Memory | |
315 | ||
316 | ## "Owned" Pointers | |
317 | ||
318 | ~~~~{.rust} | |
319 | fn main() { | |
320 | let x: ~[int] = ~[1,2,3]; | |
321 | /* x in scope */ | |
322 | { | |
323 | let y: ~[int] = ~[4,5,6]; | |
324 | /* x, y in scope */ | |
325 | } | |
326 | /* x in scope */ | |
327 | } | |
328 | ~~~~ | |
329 | ||
330 | # Pointers and Memory | |
331 | ||
332 | ## "Owned" Pointers | |
333 | ||
334 | ~~~~{.rust} | |
335 | fn main() { | |
336 | let x: ~[int] = ~[1,2,3]; // malloc |----+ | |
337 | /* ... */ // | | |
338 | { // | | |
339 | let y: ~[int] = ~[4,5,6]; // malloc |-+ | | |
340 | /* ... */ // | | | |
341 | } // free <---+ | | |
342 | /* ... */ // | | |
343 | } // free <------+ | |
344 | ~~~~ | |
345 | ||
346 | # Pointers and Memory | |
347 | ||
348 | ## "Owned" Pointers | |
349 | ||
350 | ~~~~{.rust} | |
351 | fn f0() -> ~[int] { | |
352 | return ~[1,2,3]; // returning ownership | |
353 | } | |
354 | fn f1() -> ~[int] { | |
355 | let a = ~[1,2,3]; | |
356 | let b = a; | |
357 | return a; // error: use of moved value: `a` | |
358 | } | |
359 | fn f2() -> ~[int] { | |
360 | let a = ~[1,2,3]; | |
361 | let b = a.clone(); | |
362 | return a; // fine now; `a` and `b` both valid | |
363 | } | |
364 | ~~~~ | |
365 | ||
366 | # Pointers and Memory | |
367 | ||
368 | ## "Owned" Pointers | |
369 | ||
370 | ~~~~{.rust} | |
371 | #[deriving(Clone)] | |
372 | enum List<T> { Cons(T, ~List<T>), Nil } | |
373 | ||
374 | fn f3() -> ~List<int> { | |
375 | let mut a = ~Cons(1, ~Cons(2, ~Nil)) | |
376 | /* a is mutable */ | |
377 | let b = a; | |
378 | /* can no longer use a, b is immutable */ | |
379 | let mut c = b.clone(); | |
380 | /* can use both b and c */ | |
381 | return b; | |
382 | } | |
383 | ~~~~ | |
384 | ||
385 | # Pointers and Memory | |
386 | ||
387 | ## Dispreferred Style | |
388 | ||
389 | ~~~~{.rust} | |
390 | type t8 = (u32,u32,u32,u32,u32,u32,u32,u32); | |
391 | ||
392 | fn eight_nums() -> ~t8 { | |
393 | ~(1,2,3,4,5,6,7,8) | |
394 | } | |
395 | ||
396 | fn main() { | |
397 | let t: ~t8 = eight_nums(); | |
398 | /* ... */ | |
399 | } | |
400 | ~~~~ | |
401 | ||
402 | # Pointers and Memory | |
403 | ||
404 | ## Preferred Style | |
405 | ||
406 | ~~~~{.rust} | |
407 | type t8 = (u32,u32,u32,u32,u32,u32,u32,u32); | |
408 | ||
409 | fn eight_nums() -> t8 { | |
410 | (1,2,3,4,5,6,7,8) | |
411 | } | |
412 | ||
413 | fn main() { | |
414 | let t: ~t8 = ~eight_nums(); | |
415 | /* ... */ | |
416 | } | |
417 | ~~~~ | |
418 | ||
419 | # Pointers and Memory | |
420 | ||
421 | ## References | |
422 | ||
423 | ~~~~{.rust} | |
424 | { | |
425 | let p = Point { x: 1.2, y: 3.4 }; | |
426 | let q = & p; | |
427 | // both p and q usable | |
428 | } | |
429 | { | |
430 | let q = & Point { x: 1.2, y: 3.4 }; | |
431 | } | |
432 | { | |
433 | let p = Point { x: 1.2, y: 3.4 }; | |
434 | let r = & p.x; | |
435 | } | |
436 | ~~~~ | |
437 | ||
438 | # Pointers and Memory | |
439 | ||
440 | ## References | |
441 | ||
442 | ~~~~{.rust} | |
443 | fn eq(xl: ~List<int>, yl: ~List<int>) -> bool { | |
444 | /* elided */ | |
445 | } | |
446 | ||
447 | fn main() { | |
448 | let l1 = ~Cons(1, ~Cons (2, ~Nil)); | |
449 | let l2 = ~Cons(3, ~Cons (4, ~Nil)); | |
450 | println!("{}", eq(l1, l2)); | |
451 | println!("{:?}", l1); | |
452 | } | |
453 | ~~~~ | |
454 | ||
455 | # Pointers and Memory | |
456 | ||
457 | ## References | |
458 | ||
459 | ~~~~{.rust} | |
460 | fn eq(xl: ~List<int>, yl: ~List<int>) -> bool { | |
461 | /* elided */ | |
462 | } | |
463 | ||
464 | fn main() { | |
465 | let l1 = ~Cons(1, ~Cons (2, ~Nil)); | |
466 | let l2 = ~Cons(3, ~Cons (4, ~Nil)); | |
467 | println!("{}", eq(l1, l2)); // ownership of l1 and l2 | |
468 | // moves to eq function | |
469 | println!("{:?}", l1); // error: use of moved value! | |
470 | } | |
471 | ~~~~ | |
472 | ||
473 | # Pointers and Memory | |
474 | ||
475 | ## References | |
476 | ||
477 | ~~~~{.rust} | |
478 | fn eq(xl: ~List<int>, yl: ~List<int>) -> bool { | |
479 | /* elided */ | |
480 | } | |
481 | ||
482 | fn main() { | |
483 | let l1 = ~Cons(1, ~Cons (2, ~Nil)); | |
484 | let l2 = ~Cons(3, ~Cons (4, ~Nil)); | |
485 | println!("{}", eq(l1.clone(), l2.clone())); | |
486 | println!("{:?}", l1); | |
487 | } | |
488 | ~~~~ | |
489 | ||
490 | # Pointers and Memory | |
491 | ||
492 | ## References | |
493 | ||
494 | ~~~~{.rust} | |
495 | fn eq(xl: &List<int>, yl: &List<int>) -> bool { | |
496 | /* elided */ | |
497 | } | |
498 | ||
499 | fn main() { | |
500 | let l1 = ~Cons(1, ~Cons (2, ~Nil)); | |
501 | let l2 = ~Cons(3, ~Cons (4, ~Nil)); | |
502 | println!("{}", eq(l1, l2)); | |
503 | println!("{:?}", l1); | |
504 | } | |
505 | ~~~~ | |
506 | ||
507 | # Pointers and Memory | |
508 | ||
509 | ## References | |
510 | ||
511 | ~~~~{.rust} | |
512 | fn eq(xl: &List<int>, yl: &List<int>) -> bool { | |
513 | match (xl, yl) { | |
514 | (&Nil, &Nil) => true, | |
515 | (&Cons(x, ~ref xs), &Cons(y, ~ref ys)) | |
516 | if x == y => eq(xs, ys), | |
517 | (_, _) => false | |
518 | } | |
519 | } | |
520 | ~~~~ | |
521 | ||
522 | # Pointers and Memory | |
523 | ||
524 | ## References | |
525 | ||
526 | ~~~~{.rust} | |
527 | fn eq<T: Eq>(xl: &List<T>, yl: &List<T>) -> bool { | |
528 | match (xl, yl) { | |
529 | (&Nil, &Nil) => true, | |
530 | (&Cons(x, ~ref xs), &Cons(y, ~ref ys)) | |
531 | if x == y => eq(xs, ys), | |
532 | (_, _) => false | |
533 | } | |
534 | } | |
535 | ~~~~ | |
536 | ||
537 | # Pointers and Memory | |
538 | ||
539 | ## References and Lifetimes | |
540 | ||
541 | ~~~~{.rust} | |
542 | { | |
543 | let a = ~5; | |
544 | let mut p = &a; | |
545 | { | |
546 | let b = ~8; | |
547 | p = &b; | |
548 | } | |
549 | println!("{}", **p) | |
550 | } | |
551 | ~~~~ | |
552 | ||
553 | ||
554 | # Pointers and Memory | |
555 | ||
556 | ## References and Lifetimes | |
557 | ||
558 | ~~~~{.rust} | |
559 | { | |
560 | let a = ~5; // malloc |---+ | |
561 | let mut p = &a; // | | |
562 | { // | | |
563 | let b = ~8; // malloc |-+ | | |
564 | p = &b; // | | | |
565 | } // free <---+ | | |
566 | println!("{}", **p) // | | |
567 | } // free <-----+ | |
568 | ~~~~ | |
569 | ||
570 | ||
571 | # Pointers and Memory | |
572 | ||
573 | ## References and Lifetimes | |
574 | ||
575 | ~~~~{.rust} | |
576 | { | |
577 | let a = ~5; | |
578 | let mut p = &a; | |
579 | { | |
580 | let b = ~8; | |
581 | p = &b; // error: borrowed value does | |
582 | // not live long enough | |
583 | } | |
584 | println!("{}", **p) | |
585 | } | |
586 | ~~~~ | |
587 | # Pointers and Memory | |
588 | ||
589 | ## References, Pointers, Mutability | |
590 | ||
591 | ~~~~{.rust} | |
592 | { | |
593 | let mut x = ~5; | |
594 | *x = *x + 1; | |
595 | { | |
596 | let y = &x; | |
597 | /* x is not mutable for the rest of this block */ | |
598 | } | |
599 | /* x regains mutability */ | |
600 | } | |
601 | ~~~~ | |
602 | ||
603 | # Pointers and Memory | |
604 | ||
605 | ## References, Pointers, Mutability | |
606 | ||
607 | ~~~~{.rust} | |
608 | enum IntList { | |
609 | Cons { head: int, tail: ~IntList }, | |
610 | Nil, | |
611 | } | |
612 | { | |
613 | let mut lst = ~Cons { head: 5, tail: ~Nil }; | |
614 | { | |
615 | let y = &(lst.head); // or &((*lst).head) | |
616 | lst = ~Nil; | |
617 | println!("{}", y); | |
618 | } | |
619 | } | |
620 | ~~~~ | |
621 | ||
622 | # Pointers and Memory | |
623 | ||
624 | ## References, Pointers, Mutability | |
625 | ||
626 | ~~~~{.rust} | |
627 | enum IntList { | |
628 | Cons { head: int, tail: ~IntList }, | |
629 | Nil, | |
630 | } | |
631 | { | |
632 | let mut lst = ~Cons { head: 5, tail: ~Nil }; | |
633 | { | |
634 | let y = &(lst.head); | |
635 | lst = ~Nil; | |
636 | println!("{}", y); // BAD | |
637 | } | |
638 | } | |
639 | ~~~~ | |
640 | ||
641 | # Pointers and Memory | |
642 | ||
643 | ## Named Lifetimes | |
644 | ||
645 | ~~~~{.rust} | |
646 | fn tail<T>(lst: &List<T>) -> &List<T> { | |
647 | match *lst { | |
648 | Nil => &Nil, | |
649 | Cons(_, ~ref xs) => xs | |
650 | } | |
651 | } | |
652 | ~~~~ | |
653 | ||
654 | # Pointers and Memory | |
655 | ||
656 | ## Named Lifetimes | |
657 | ||
658 | ~~~~{.rust} | |
659 | fn tail<'s, T>(lst: &'s List<T>) -> &'s List<T> { | |
660 | match *lst { | |
661 | Nil => &Nil, | |
662 | Cons(_, ~ref xs) => xs | |
663 | } | |
664 | } | |
665 | ~~~~ | |
666 | ||
667 | # Pointers and Memory | |
668 | ||
669 | ## Reference Counting | |
670 | ||
671 | ~~~~{.rust} | |
672 | use std::rc::Rc; | |
673 | { | |
674 | let x = Rc::new([1,2,3]); | |
675 | let y = x.clone(); // two references, one vector | |
676 | assert!(x.ptr_eq(y)); | |
677 | assert!(*y.borrow() == [1,2,3]); | |
678 | } | |
679 | ~~~~ | |
680 | ||
681 | ## Garbage Collection | |
682 | ||
683 | ~~~~{.rust} | |
684 | use std::gc::Gc; | |
685 | { | |
686 | let x = Gc::new([1,2,3]); | |
687 | // etc. | |
688 | } | |
689 | ~~~~ | |
690 | ||
691 | # Pointers and Memory | |
692 | ||
693 | ## C Pointers | |
694 | ||
695 | ~~~~{.rust} | |
696 | use std::ptr::RawPtr; | |
697 | ||
698 | #[link(name="foo")] | |
699 | extern { | |
700 | fn unsafe_get() -> *int; | |
701 | } | |
702 | ||
703 | fn safe_get() -> Option<int> { | |
704 | unsafe { | |
705 | let i = unsafe_get(); | |
706 | i.to_option() | |
707 | } | |
708 | } | |
709 | ~~~~ | |
710 | ||
711 | # Closures | |
712 | ||
713 | # Closures | |
714 | ||
715 | > [...] Lambdas are relegated to relative obscurity until Java makes them | |
716 | > popular by not having them. | |
717 | > | |
718 | > —James Iry, "A Brief, Incomplete, and Mostly Wrong History of Programming | |
719 | > Languages" | |
720 | ||
721 | # Closures | |
722 | ||
723 | ## Functions | |
724 | ||
725 | ~~~~{.rust} | |
726 | fn main() { | |
727 | let x = 5; | |
728 | fn inner(y: int) -> int { | |
729 | return x + y; | |
730 | } | |
731 | println!("{}", inner(1)); | |
732 | } | |
733 | ~~~~ | |
734 | ||
735 | # Closures | |
736 | ||
737 | ## Functions Do NOT Close Over Env | |
738 | ||
739 | ~~~~{.rust} | |
740 | fn main() { | |
741 | let x = 5; | |
742 | fn inner(y: int) -> int { | |
743 | return x + y; // error: can't capture dynamic env | |
744 | } | |
745 | println!("{}", inner(1)); | |
746 | } | |
747 | ~~~~ | |
748 | ||
749 | # Closures | |
750 | ||
751 | ## Stack Closure | |
752 | ||
753 | ~~~~{.rust} | |
754 | fn main() { | |
755 | let x = 5; | |
756 | let inner = |y| x + y; | |
757 | println!("{}", inner(1)); | |
758 | } | |
759 | ~~~~ | |
760 | ||
761 | ## Stack Closure with Type Annotations | |
762 | ||
763 | ~~~~{.rust} | |
764 | fn main() { | |
765 | let x = 5; | |
766 | let inner = |y: int| -> int { x + y }; | |
767 | println!("{}", inner(1)); | |
768 | } | |
769 | ~~~~ | |
770 | ||
771 | # Closures | |
772 | ||
773 | ## Stack Closures | |
774 | ||
775 | ~~~~{.rust} | |
776 | fn my_map<A,B>(f: |&A|->B, l: &List<A>) -> List<B> { | |
777 | match *l { | |
778 | Nil => Nil, | |
779 | Cons(ref x, ~ref xs) => | |
780 | Cons(f(x)), ~my_map(f, xs)) | |
781 | } | |
782 | } | |
783 | ||
784 | fn main() { | |
785 | fn incr(x: &int) -> int { x + 1 } | |
786 | let l = ~Cons(1, ~Cons(2, ~Cons(3, ~Nil))); | |
787 | println!("{:?}", my_map(|x| x + 1, l)); | |
788 | println!("{:?}", my_map(incr, l)); | |
789 | } | |
790 | ~~~~ | |
791 | ||
792 | # Closures | |
793 | ||
794 | ## Owned Closures | |
795 | ||
796 | ~~~~{.rust} | |
797 | use std::task::spawn; | |
798 | ||
799 | fn main() { | |
800 | let x = ~5; | |
801 | spawn(proc() { | |
802 | println!("{}", x); | |
803 | }); | |
804 | // x is now owned by the proc above | |
805 | } | |
806 | ~~~~ | |
807 | ||
808 | # Methods | |
809 | ||
810 | ## Methods on a Struct | |
811 | ||
812 | ~~~~{.rust} | |
813 | use std::f64::{sqrt,pow}; | |
814 | struct Point { x: f64, y: f64 } | |
815 | impl Point { | |
816 | fn magnitude(&self) -> f64 { | |
817 | sqrt(pow(self.x,2.0)+pow(self.y,2.0)) | |
818 | } | |
819 | fn new((my_x, my_y): (f64, f64)) -> Point { | |
820 | Point { x: my_x, y: my_y } | |
821 | } | |
822 | } | |
823 | fn main() { | |
824 | let p = Point::new((2.0,4.0)); | |
825 | println!("{}", p.magnitude()); | |
826 | } | |
827 | ~~~~ | |
828 | ||
829 | # Methods | |
830 | ||
831 | ## Methods on an Enum | |
832 | ||
833 | ~~~~{.rust} | |
834 | impl<T> List<T> { | |
835 | fn is_empty(&self) -> bool { | |
836 | match self { | |
837 | &Nil => true, | |
838 | &Cons(_, _) => false, | |
839 | } | |
840 | } | |
841 | } | |
842 | ~~~~ | |
843 | ||
844 | # Traits | |
845 | ||
846 | ## Head of a List By Reference | |
847 | ~~~~{.rust} | |
848 | fn head<'a, T>(lst: &'a List<T>) -> Option<&'a T> { | |
849 | match lst { | |
850 | &Nil => None, | |
851 | &Cons(ref hd, _) => Some(hd) | |
852 | } | |
853 | } | |
854 | ~~~~ | |
855 | ||
856 | # Traits | |
857 | ||
858 | ## Head of a List By Value | |
859 | ~~~~{.rust} | |
860 | fn head<T>(lst: &List<T>) -> Option<T> { | |
861 | match lst { | |
862 | &Nil => None, | |
863 | &Cons(ref hd, _) => Some(*hd) | |
864 | } | |
865 | } | |
866 | ~~~~ | |
867 | ||
868 | # Traits | |
869 | ||
870 | ## Head of a List By Value | |
871 | ~~~~{.rust} | |
872 | fn head<T>(lst: &List<T>) -> Option<T> { | |
873 | match lst { | |
874 | &Nil => None, | |
875 | &Cons(ref hd, _) => Some(*hd) | |
876 | // cannot move out of dereference of & pointer | |
877 | } | |
878 | } | |
879 | ~~~~ | |
880 | ||
881 | # Traits | |
882 | ||
883 | ## Head of a List By Value | |
884 | ~~~~{.rust} | |
885 | fn head<T: Clone>(lst: &List<T>) -> Option<T> { | |
886 | match lst { | |
887 | &Nil => None, | |
888 | &Cons(ref hd, _) => Some(hd.clone()) | |
889 | } | |
890 | } | |
891 | ~~~~ | |
892 | ||
893 | # Traits | |
894 | ||
895 | ## Declaring Traits | |
896 | ~~~~{.rust} | |
897 | trait Printable { | |
898 | fn print(&self); | |
899 | } | |
900 | ||
901 | impl Printable for int { | |
902 | fn print(&self) { println!("{}", *self) } | |
903 | } | |
904 | ||
905 | impl Printable for bool { | |
906 | fn print(&self) { println!("{}", *self) } | |
907 | } | |
908 | ||
909 | fn main() { | |
910 | 5.print(); true.print(); | |
911 | } | |
912 | ~~~~ | |
913 | ||
914 | # Traits | |
915 | ||
916 | ## Using Multiple Traits | |
917 | ||
918 | ~~~~{.rust} | |
919 | fn print_head<T: Clone+Printable>(lst: &List<T>) { | |
920 | match lst { | |
921 | &Nil => { println!("Nothing!") } | |
922 | &Cons(ref hd, _) => { hd.clone().print() } | |
923 | } | |
924 | } | |
925 | ~~~~ | |
926 | ||
927 | # Traits | |
928 | ||
929 | ## Static Dispatch | |
930 | ||
931 | ~~~~{.rust} | |
932 | fn printAll<T: Printable>(vec: &[T]) { | |
933 | for p in vec.iter() { p.print() } | |
934 | } | |
935 | fn main() { | |
936 | printAll([1, 2, 3]); | |
937 | } | |
938 | ~~~~ | |
939 | ||
940 | ## Dynamic Dispatch | |
941 | ||
942 | ~~~~{.rust} | |
943 | fn print_all(vec: &[~Printable]) { | |
944 | for p in vec.iter() { p.print() } | |
945 | } | |
946 | fn main() { | |
947 | print_all([~1 as ~Printable, ~true as ~Printable]); | |
948 | } | |
949 | ~~~~ | |
950 | ||
951 | # Tasks and Communication | |
952 | ||
953 | ## Tasks | |
954 | ||
955 | ~~~~{.rust} | |
956 | fn main() { | |
957 | spawn(proc() { | |
958 | println!("Hello from another task!"); | |
959 | }); | |
960 | println!("Hello from the parent task!"); | |
961 | } | |
962 | ~~~~ | |
963 | ||
964 | # Tasks and Communication | |
965 | ||
966 | ## Communication | |
967 | ||
968 | ~~~~{.rust} | |
969 | fn main() { | |
970 | let (port, chan): (Port<int>, Chan<int>) = Chan::new(); | |
971 | spawn(proc() { | |
972 | chan.send(some_computation()); | |
973 | }); | |
974 | some_other_computation(); | |
975 | let result = port.recv(); | |
976 | } | |
977 | ~~~~ | |
978 | ||
979 | # Tasks and Communication | |
980 | ||
981 | ## Atomic Reference Counting | |
982 | ||
983 | ~~~~{.rust} | |
984 | fn main() { | |
985 | let parent_copy = Arc::new(something_very_large()); | |
986 | let (port, chan) = Chan::new(); | |
987 | chan.send(parent_copy.clone()); | |
988 | spawn(proc() { | |
989 | let task_copy = port.recv(); | |
990 | task_copy.get().do_something(); | |
991 | }); | |
992 | parent_copy.get().do_something_else(); | |
993 | } | |
994 | ~~~~ | |
995 | ||
996 | # Tasks and Communication | |
997 | ||
998 | ## Failure | |
999 | ||
1000 | ~~~~{.rust} | |
1001 | fn main() { | |
1002 | let r : Result<int, ()> = try(proc() { | |
1003 | if some_operation_succeeds() { | |
1004 | return 5; | |
1005 | } else { | |
1006 | fail!("Hark! An error!"); | |
1007 | } | |
1008 | }); | |
1009 | match r { | |
1010 | Ok(i) => println!("Got {}", i), | |
1011 | Err(_) => println!("Hark!"), | |
1012 | }; | |
1013 | } | |
1014 | ~~~~ | |
1015 | ||
1016 | # Crates and Modules | |
1017 | ||
1018 | - A "crate" is a compilation unit; `rustc` produces a single crate | |
1019 | if it is run (either a library or an executable.) | |
1020 | - A module is a grouping of definitions. Modules can be hierarchical | |
1021 | and can be defined in a single file in `mod { ... }` blocks, or in | |
1022 | separate files. | |
1023 | ||
1024 | # Crates and Modules | |
1025 | ||
1026 | ## main.rs | |
1027 | ||
1028 | ~~~~{.rust} | |
1029 | mod mylist { | |
1030 | pub enum List<T> { Cons(T, ~List<T>), Nil } | |
1031 | pub fn from_vec<T>(mut vec : ~[T]) -> ~List<T> { ... } | |
1032 | impl<T> List<T> { | |
1033 | pub fn length(&self) -> int { ... } | |
1034 | } | |
1035 | } | |
1036 | ||
1037 | fn main() { | |
1038 | let v = ~[1,2,3]; | |
1039 | let l = ::mylist::from_vec(v); | |
1040 | /* ... */ | |
1041 | } | |
1042 | ~~~~ | |
1043 | ||
1044 | # Crates and Modules | |
1045 | ||
1046 | ## mylist.rs or mylist/mod.rs | |
1047 | ||
1048 | ~~~~{.rust} | |
1049 | mod mylist { | |
1050 | pub enum List<T> { Cons(T, ~List<T>), Nil } | |
1051 | pub fn from_vec<T>(mut vec : ~[T]) -> ~List<T> { ... } | |
1052 | impl<T> List<T> { | |
1053 | pub fn length(&self) -> int { ... } | |
1054 | } | |
1055 | } | |
1056 | ~~~~ | |
1057 | ||
1058 | ## main.rs | |
1059 | ||
1060 | ~~~~{.rust} | |
1061 | mod mylist; | |
1062 | main() { | |
1063 | let v = ~[1,2,3]; | |
1064 | let l = ::mylist::from_vec(v); | |
1065 | /* ... */ | |
1066 | } | |
1067 | ~~~~ | |
1068 | ||
1069 | # Crates and Modules | |
1070 | ## main.rs | |
1071 | ||
1072 | ~~~~{.rust} | |
1073 | use mylist::from_vec; | |
1074 | mod mylist; | |
1075 | ||
1076 | main() { | |
1077 | let v = ~[1,2,3]; | |
1078 | let l = from_vec(v); | |
1079 | /* ... */ | |
1080 | } | |
1081 | ~~~~ | |
1082 | ||
1083 | # Crates and Modules | |
1084 | ## Crate Metadata | |
1085 | ||
1086 | ~~~~{.rust} | |
1087 | #[crate_id = "mycrate#1.2"]; | |
1088 | #[crate_type = "lib"]; | |
1089 | ~~~~ | |
1090 | ||
1091 | ## Requesting Crate Metadata | |
1092 | ||
1093 | ~~~~{.rust} | |
1094 | extern crate mycrate "mycrate#1.2"; | |
1095 | extern crate oldmycrate "mycrate#0.6"; | |
1096 | ~~~~ | |
1097 | ||
1098 | # The Future | |
1099 | ||
1100 | # The Future | |
1101 | ||
1102 | \begin{center} | |
1103 | \includegraphics[width=.9\textwidth]{imgs/flying-machines.jpg} | |
1104 | \end{center} | |
1105 | ||
1106 | # The Future | |
1107 | ||
1108 | ## Possible Syntax Changes | |
1109 | ||
1110 | - `~foo` might become `box foo` | |
1111 | - `~[T]` might become `Vec<T>` | |
1112 | - Operator overloading | |
1113 | ||
1114 | ## Possible Language Changes | |
1115 | ||
1116 | - Speculations about inheritance, subtyping | |
1117 | - Stronger restrictions on `unsafe` code | |
1118 | ||
1119 | ## Standard Library Improvements | |
1120 | ||
1121 | ## Package Manager |
1 | DEPS="rust.tex rust.md" | |
2 | redo-ifchange $DEPS | |
3 | xelatex --output-directory build 1>&2 rust.tex | |
4 | mv build/rust.pdf $3 |
1 | redo-ifchange rust.md | |
2 | pandoc -f markdown -t beamer --standalone --highlight-style haddock \ | |
3 | -V theme=Boadilla -V colortheme=beaver --template=my.beamer <rust.md >$3 |
1 | #include <stdio.h> | |
2 | #include <stdlib.h> | |
3 | ||
4 | typedef struct { | |
5 | int x, y; | |
6 | } point; | |
7 | ||
8 | point add(point a, point b) | |
9 | { | |
10 | point result = { a.x + b.x, a.y + b.y }; | |
11 | return result; | |
12 | } | |
13 | ||
14 | int main(int argc, char* argv[]) | |
15 | { | |
16 | point a = { 1, 2 }; | |
17 | point* b = malloc(sizeof(point)); | |
18 | b->x = 4; | |
19 | b->y = 3; | |
20 | point c = add(a, *b); | |
21 | printf("{.x = %d, .y = %d}\n", c.x, c.y); | |
22 | return 0; | |
23 | } |
1 | #include "stdio.h" | |
2 | #include "stdlib.h" | |
3 | #include <iostream> | |
4 | ||
5 | struct point { | |
6 | int x, y; | |
7 | point(int _x, int _y) { | |
8 | x = _x; y = _y; | |
9 | } | |
10 | point add(point other) { | |
11 | return point(x + other.x, y + other.y); | |
12 | } | |
13 | }; | |
14 | ||
15 | int main(int argc, char* argv[]) { | |
16 | point a(1, 2); | |
17 | point* b = new point(4, 3); | |
18 | point c = a.add(*b); | |
19 | std::cout << "{.x = " << c.x; | |
20 | std::cout << ", .y = " << c.y << "}" << std::endl; | |
21 | delete b; | |
22 | } |
1 | import core.memory; | |
2 | import std.stdio; | |
3 | ||
4 | struct Point { | |
5 | int x, y; | |
6 | Point add(Point other) { | |
7 | return Point(this.x + other.x, this.y + other.y); | |
8 | } | |
9 | } | |
10 | ||
11 | void main() { | |
12 | Point a = Point(1, 2); | |
13 | Point* b = cast(Point*)GC.malloc(Point.sizeof); | |
14 | b.x = 4; | |
15 | b.y = 3; | |
16 | writeln(a.add(*b)); | |
17 | GC.free(b); | |
18 | } |
1 | data Point = { x, y : Int } | |
2 | ||
3 | addPoint : Point -> Point -> Point | |
4 | addPoint p1 p2 = { x = p1.x + p2.x, y = p1.y + p2.y } | |
5 | ||
6 | main : () | |
7 | main = { let a = { x = 1, y = 2 } | |
8 | ; let b = malloc { x = 4, y = 3} | |
9 | ; print (addPoint a (deref b)) | |
10 | ; free(b) | |
11 | } |
1 | package main | |
2 | ||
3 | import "fmt" | |
4 | ||
5 | type Point struct { X, Y int } | |
6 | ||
7 | func (a Point) add(b Point) Point { | |
8 | return Point{ a.X + b.X, a.Y + b.Y } | |
9 | } | |
10 | ||
11 | func main() { | |
12 | a := Point{1, 2} | |
13 | b := new(Point) | |
14 | b.X, b.Y = 4, 3 | |
15 | fmt.Println(a.add(*b)) | |
16 | } |
1 | type Point = tuple[x: int, y: int] | |
2 | ||
3 | proc add(a: Point, b: Point): Point = | |
4 | (x: a.x + b.x, y: a.y + b.y) | |
5 | ||
6 | var a : Point | |
7 | var b : ptr Point | |
8 | ||
9 | a = (x: 1, y: 2) | |
10 | b = cast[ptr Point](alloc(sizeof(Point))) | |
11 | b.x = 4 | |
12 | b.y = 3 | |
13 | echo(add(a, b[])) | |
14 | dealloc(b) |
1 | struct Point { | |
2 | x: int, | |
3 | y: int | |
4 | } | |
5 | ||
6 | impl Point { | |
7 | fn add(self, other: Point) -> Point { | |
8 | Point { x: self.x + other.x, | |
9 | y: self.y + other.y } | |
10 | } | |
11 | } | |
12 | ||
13 | fn main() { | |
14 | let a = Point { x: 1, y: 2 }; | |
15 | let b = ~Point { x: 4, y: 3 }; | |
16 | println!("{:?}", a.add(*b)); | |
17 | } |
1 | if [ -e regexp ]; then rm regexp; fi |
1 | redo-ifchange regexp |
1 | use re::instruction::{Instr,IChar,IMatch,IJmp,ISplit}; | |
2 | use std::vec::append; | |
3 | mod instruction; | |
4 | ||
5 | /* A regular expression parse tree */ | |
6 | enum Regexp { | |
7 | RChar(char), | |
8 | RSeq(~Regexp, ~Regexp), | |
9 | RChc(~Regexp, ~Regexp), | |
10 | RRep(~Regexp), | |
11 | } | |
12 | ||
13 | /* We're assuming a prefix regexp here. That means that we have | |
14 | * the following operators: | |
15 | * .ab => ab | |
16 | * |ab => a|b | |
17 | * *a => a* | |
18 | * but these nest, so (ab|c)* would become | |
19 | * *|c.ab | |
20 | * This is easier to parse. Deal with it. | |
21 | */ | |
22 | fn parse<'a>(s: &'a str) -> (&'a str, Regexp) { | |
23 | match s.char_at(0) { | |
24 | '.' => { let (s1, r1) = parse(s.slice_from(1)); | |
25 | let (s2, r2) = parse(s1); | |
26 | (s2, RSeq(~r1, ~r2)) }, | |
27 | '|' => { let (s1, r1) = parse(s.slice_from(1)); | |
28 | let (s2, r2) = parse(s1); | |
29 | (s2, RChc(~r1, ~r2)) }, | |
30 | '*' => { let (s1, r1) = parse(s.slice_from(1)); | |
31 | (s1, RRep(~r1)) }, | |
32 | c => (s.slice_from(1), RChar(c)), | |
33 | } | |
34 | } | |
35 | ||
36 | /* Compiling an AST for regexps to the instructions */ | |
37 | fn emit(r: &Regexp, i: uint) -> (uint, ~[Instr]) { | |
38 | match *r { | |
39 | RChar(c) => { (i+1, ~[IChar(c)]) }, | |
40 | RSeq(ref a, ref b) => | |
41 | { let (ai, v1) = emit(*a, i); | |
42 | let (bi, v2) = emit(*b, ai); | |
43 | (bi, append(v1, v2)) }, | |
44 | RChc(ref a, ref b) => | |
45 | { let (ai, v1) = emit(*a, i + 1); | |
46 | let (bi, v2) = emit(*b, ai + 1); | |
47 | let spl = ~[ ISplit(i + 1, ai + 1) ]; | |
48 | let jmp = ~[ IJmp(ai) ]; | |
49 | (bi, append(spl, append(v1, append(jmp, v2)))) }, | |
50 | RRep(ref a) => | |
51 | { let (ai, v1) = emit(*a, i + 1); | |
52 | let spl = ~[ ISplit(i + 1, ai + 1) ]; | |
53 | let jmp = ~[ IJmp(i) ]; | |
54 | (ai + 1, append(spl, append(v1, jmp))) }, | |
55 | } | |
56 | } | |
57 | ||
58 | /* A wrapper over these processes */ | |
59 | pub fn compile(s: &str) -> ~[Instr] { | |
60 | let (_, re) = parse(s); | |
61 | println!("{:?}", re); | |
62 | let (_, ins) = emit(&re, 0); | |
63 | println!("{:?}", ins); | |
64 | return append(ins, [IMatch]); | |
65 | } |
1 | /* A single instruction as used in the VM-based matcher */ | |
2 | #[deriving(Clone)] | |
3 | pub enum Instr { | |
4 | IChar(char), /* match a character or fail */ | |
5 | IMatch, /* match anything successfully */ | |
6 | IJmp(uint) , /* jump to instr i */ | |
7 | ISplit(uint, uint), /* try both instrs i and j */ | |
8 | } |
1 | pub use re::compile::compile; | |
2 | pub use re::instruction::{Instr,IChar,IMatch,IJmp,ISplit}; | |
3 | pub use re::recursive::eval; | |
4 | pub use re::stack::eval; | |
5 | pub mod compile; | |
6 | pub mod instruction; | |
7 | pub mod recursive; | |
8 | pub mod stack; |
1 | use re::instruction::{Instr,IChar,IMatch,IJmp,ISplit}; | |
2 | mod instruction; | |
3 | ||
4 | /* We wrap the real evaluation function, as we're always going to | |
5 | * start executing instruction 0 with no string matched. */ | |
6 | pub fn eval(instrs: &[Instr], input: &str) -> bool { | |
7 | eval1(instrs, input, 0, 0) | |
8 | } | |
9 | ||
10 | /* We use the Rust stack as our stack in this naive recursive | |
11 | * implementation. */ | |
12 | fn eval1(instrs: &[Instr], input: &str, pc: uint, cc: uint) -> bool { | |
13 | match instrs[pc] { | |
14 | IChar(_) if cc >= input.len() => return false, | |
15 | IChar(c) if c == input.char_at(cc) => | |
16 | eval1(instrs, input, pc + 1, cc + 1), | |
17 | IChar(_) => return false, | |
18 | IMatch => return true, | |
19 | IJmp(i) => eval1(instrs, input, i, cc), | |
20 | ISplit(i, _) if eval1(instrs, input, i, cc) => true, | |
21 | ISplit(_, j) => eval1(instrs, input, j, cc), | |
22 | } | |
23 | } |
1 | use re::instruction::{Instr,IChar,IMatch,IJmp,ISplit}; | |
2 | mod instruction; | |
3 | ||
4 | /* The state of a program can be unambiguously specified by | |
5 | * a current instruction and a current position in the string. */ | |
6 | struct EvalState { pc: uint, cc: uint } | |
7 | ||
8 | /* An evaluator that maintains a manual, mutable stack for doing | |
9 | * regular-expression matching. */ | |
10 | pub fn eval(instrs: &[Instr], input: &str) -> bool { | |
11 | let mut stack = ~[ EvalState {pc: 0, cc: 0} ]; | |
12 | ||
13 | while stack.len() > 0 { | |
14 | let st = stack.pop(); | |
15 | match instrs[st.pc] { | |
16 | IChar(_) if st.cc >= input.len() => | |
17 | continue, | |
18 | IChar(c) if c == input.char_at(st.cc) => | |
19 | stack.push(EvalState { pc: st.pc + 1, cc: st.cc + 1 }), | |
20 | IChar(_) => | |
21 | continue, | |
22 | IMatch => | |
23 | return true, | |
24 | IJmp(i) => | |
25 | stack.push(EvalState { pc: i, cc: st.cc }), | |
26 | ISplit(i, j) => { | |
27 | stack.push(EvalState { pc: j, cc: st.cc }); | |
28 | stack.push(EvalState { pc: i, cc: st.cc }); | |
29 | }, | |
30 | } | |
31 | } | |
32 | return false; | |
33 | } |
1 | DEPS="regexp.rs re/compile.rs re/instruction.rs re/mod.rs re/recursive.rs re/stack.rs" | |
2 | redo-ifchange $DEPS | |
3 | rustc regexp.rs -o $3 |
1 | /* This is a basic implementation of a regular expression matcher, | |
2 | * based on Henry Spencer's virtual-machine approach to regular | |
3 | * expression matching outlined by Russ Cox here: | |
4 | * http://swtch.com/~rsc/regexp/regexp2.html | |
5 | * | |
6 | * For ease of parsing, I'm using a highly non-standard Polish | |
7 | * notation for regular expressions, in which . and | are | |
8 | * prefix binary operators for catenation and choice, respectively, | |
9 | * and * is a prefix unary operator for repetition. */ | |
10 | use re::compile; | |
11 | mod re; | |
12 | ||
13 | fn main() { | |
14 | /* our sample regexp corresponds to /ab*c/ in | |
15 | * the usual notation. */ | |
16 | let re = compile("..a*bc"); | |
17 | println("Recursive:"); | |
18 | println!(" match(re, \"abbbc\")\t== {}", | |
19 | ::re::recursive::eval(re, "abbbc")); | |
20 | println!(" match(re, \"ac\")\t== {}", | |
21 | ::re::recursive::eval(re, "ac")); | |
22 | println!(" match(re, \"abd\")\t== {}", | |
23 | ::re::recursive::eval(re, "abd")); | |
24 | println("Manual Stack:"); | |
25 | println!(" match(re, \"abbbc\")\t== {}", | |
26 | ::re::stack::eval(re, "abbbc")); | |
27 | println!(" match(re, \"ac\")\t== {}", | |
28 | ::re::stack::eval(re, "ac")); | |
29 | println!(" match(re, \"abd\")\t== {}", | |
30 | ::re::stack::eval(re, "abd")); | |
31 | } |