@@ -899,51 +899,58 @@ express that `f` requires no explicit `return`, as if it returns
899
899
control to the caller, it returns a value (true because it never returns
900
900
control).
901
901
902
- #### Pure functions
902
+ #### Predicate functions
903
903
904
- A pure function declaration is identical to a function declaration, except that
905
- it is declared with the additional keyword ` pure ` . In addition, the typechecker
906
- checks the body of a pure function with a restricted set of typechecking rules.
907
- A pure function
904
+ Any pure boolean function is called a * predicate function* , and may be used in
905
+ a [ constraint] ( #constraints ) , as part of the static [ typestate
906
+ system] ( #typestate-system ) . A predicate declaration is identical to a function
907
+ declaration, except that it is declared with the additional keyword ` pure ` . In
908
+ addition, the typechecker checks the body of a predicate with a restricted set
909
+ of typechecking rules. A predicate
908
910
909
911
* may not contain an assignment or self-call expression; and
910
- * may only call other pure functions , not general functions.
912
+ * may only call other predicates , not general functions.
911
913
912
- An example of a pure function :
914
+ An example of a predicate :
913
915
914
916
~~~~
915
917
pure fn lt_42(x: int) -> bool {
916
918
return (x < 42);
917
919
}
918
920
~~~~
919
921
920
- Pure functions may call other pure functions:
922
+ A non-boolean function may also be declared with ` pure fn ` . This allows
923
+ predicates to call non-boolean functions as long as they are pure. For example:
921
924
922
925
~~~~ {.xfail-test}
923
926
pure fn pure_length<T>(ls: list<T>) -> uint { /* ... */ }
924
927
925
928
pure fn nonempty_list<T>(ls: list<T>) -> bool { pure_length(ls) > 0u }
926
929
~~~~
927
930
931
+ In this example, ` nonempty_list ` is a predicate---it can be used in a
932
+ typestate constraint---but the auxiliary function ` pure_length ` is
933
+ not.
934
+
928
935
* TODO:* should actually define referential transparency.
929
936
930
937
The effect checking rules previously enumerated are a restricted set of
931
938
typechecking rules meant to approximate the universe of observably
932
939
referentially transparent Rust procedures conservatively. Sometimes, these
933
940
rules are * too* restrictive. Rust allows programmers to violate these rules by
934
- writing pure functions that the compiler cannot prove to be referentially
941
+ writing predicates that the compiler cannot prove to be referentially
935
942
transparent, using an escape-hatch feature called "unchecked blocks". When
936
943
writing code that uses unchecked blocks, programmers should always be aware
937
944
that they have an obligation to show that the code * behaves* referentially
938
945
transparently at all times, even if the compiler cannot * prove* automatically
939
946
that the code is referentially transparent. In the presence of unchecked
940
947
blocks, the compiler provides no static guarantee that the code will behave as
941
948
expected at runtime. Rather, the programmer has an independent obligation to
942
- verify the semantics of the pure functions they write.
949
+ verify the semantics of the predicates they write.
943
950
944
951
* TODO:* last two sentences are vague.
945
952
946
- An example of a pure function that uses an unchecked block:
953
+ An example of a predicate that uses an unchecked block:
947
954
948
955
~~~~
949
956
# import std::list::*;
@@ -965,7 +972,7 @@ pure fn pure_length<T>(ls: list<T>) -> uint {
965
972
966
973
Despite its name, ` pure_foldl ` is a ` fn ` , not a ` pure fn ` , because there is no
967
974
way in Rust to specify that the higher-order function argument ` f ` is a pure
968
- function. So, to use ` foldl ` in a pure list length function that a pure function
975
+ function. So, to use ` foldl ` in a pure list length function that a predicate
969
976
could then use, we must use an ` unchecked ` block wrapped around the call to
970
977
` pure_foldl ` in the definition of ` pure_length ` .
971
978
@@ -1129,8 +1136,8 @@ looks like:
1129
1136
1130
1137
The only exception is that the body of the class constructor begins
1131
1138
with all the class's fields uninitialized, and is allowed to -- in
1132
- fact, must -- initialize all the fields. The compiler enforces this
1133
- invariant.
1139
+ fact, must -- initialize all the fields. A special case in the
1140
+ typestate pass enforces this invariant.
1134
1141
1135
1142
Usually, the class constructor stores its argument or arguments in the
1136
1143
class's named fields. In this case, the ` file_descriptor ` 's data field
@@ -1299,7 +1306,7 @@ type.
1299
1306
1300
1307
~~~~
1301
1308
# trait shape { }
1302
- # impl int: shape { }
1309
+ # impl of shape for int { }
1303
1310
# let mycircle = 0;
1304
1311
1305
1312
let myshape: shape = mycircle as shape;
@@ -1325,7 +1332,7 @@ An _implementation item_ provides an implementation of a
1325
1332
1326
1333
type circle = {radius: float, center: point};
1327
1334
1328
- impl circle: shape {
1335
+ impl circle_shape of shape for circle {
1329
1336
fn draw(s: surface) { do_draw_circle(s, self); }
1330
1337
fn bounding_box() -> bounding_box {
1331
1338
let r = self.radius;
@@ -1363,10 +1370,10 @@ specified, after the `impl` keyword.
1363
1370
~~~~
1364
1371
# trait seq<T> { }
1365
1372
1366
- impl<T> ~[T]: seq<T> {
1373
+ impl <T> of seq<T> for ~[T] {
1367
1374
/* ... */
1368
1375
}
1369
- impl u32: seq<bool> {
1376
+ impl of seq<bool> for u32 {
1370
1377
/* Treat the integer as a sequence of bits */
1371
1378
}
1372
1379
~~~~
@@ -1927,15 +1934,13 @@ x <- copy y;
1927
1934
1928
1935
The former is just more terse and familiar.
1929
1936
1930
- #### Compound assignment expressions
1937
+ #### Operator- assignment expressions
1931
1938
1932
1939
The ` + ` , ` - ` , ` * ` , ` / ` , ` % ` , ` & ` , ` | ` , ` ^ ` , ` << ` , ` >> ` , and ` >>> `
1933
1940
operators may be composed with the ` = ` operator. The expression `lval
1934
1941
OP= val` is equivalent to ` lval = lval OP val` . For example, ` x = x +
1935
1942
1` may be written as ` x += 1`.
1936
1943
1937
- Any such expression always has the [ ` nil ` ] ( #primitive-types ) type.
1938
-
1939
1944
#### Operator precedence
1940
1945
1941
1946
The precedence of Rust binary operators is ordered as follows, going
@@ -2069,6 +2074,31 @@ A `loop` expression denotes an infinite loop:
2069
2074
loop_expr : "loop" '{' block '}';
2070
2075
~~~~~~~~
2071
2076
2077
+ For a block ` b ` , the expression ` loop b ` is semantically equivalent to
2078
+ ` while true b ` . However, ` loop ` s differ from ` while ` loops in that the
2079
+ typestate analysis pass takes into account that ` loop ` s are infinite.
2080
+
2081
+ For example, the following (contrived) function uses a ` loop ` with a
2082
+ ` return ` expression:
2083
+
2084
+ ~~~~
2085
+ fn count() -> bool {
2086
+ let mut i = 0;
2087
+ loop {
2088
+ i += 1;
2089
+ if i == 20 { return true; }
2090
+ }
2091
+ }
2092
+ ~~~~
2093
+
2094
+ This function compiles, because typestate recognizes that the ` loop `
2095
+ never terminates (except non-locally, with ` return ` ), thus there is no
2096
+ need to insert a spurious ` fail ` or ` return ` after the ` loop ` . If ` loop `
2097
+ were replaced with ` while true ` , the function would be rejected
2098
+ because from the compiler's perspective, there would be a control path
2099
+ along which ` count ` does not return a value (that is, if the loop
2100
+ condition is always false).
2101
+
2072
2102
### Break expressions
2073
2103
2074
2104
~~~~~~~~ {.ebnf .gram}
@@ -2510,7 +2540,7 @@ macro-generated and user-written code can cause unintentional capture.
2510
2540
Future versions of Rust will address these issues.
2511
2541
2512
2542
2513
- # Type system
2543
+ # Types and typestates
2514
2544
2515
2545
## Types
2516
2546
@@ -2728,7 +2758,7 @@ trait printable {
2728
2758
fn to_str() -> ~str;
2729
2759
}
2730
2760
2731
- impl ~str: printable {
2761
+ impl of printable for ~str {
2732
2762
fn to_str() -> ~str { self }
2733
2763
}
2734
2764
@@ -2775,7 +2805,7 @@ trait printable {
2775
2805
fn to_str() -> ~str;
2776
2806
}
2777
2807
2778
- impl ~str: printable {
2808
+ impl of printable for ~str {
2779
2809
fn to_str() -> ~str { self }
2780
2810
}
2781
2811
~~~~~~
@@ -2936,7 +2966,7 @@ Local variables are not initialized when allocated; the entire frame worth of
2936
2966
local variables are allocated at once, on frame-entry, in an uninitialized
2937
2967
state. Subsequent statements within a function may or may not initialize the
2938
2968
local variables. Local variables can be used only after they have been
2939
- initialized; this is enforced by the compiler .
2969
+ initialized; this condition is guaranteed by the typestate system .
2940
2970
2941
2971
References are created for function arguments. If the compiler can not prove
2942
2972
that the referred-to value will outlive the reference, it will try to set
0 commit comments