Skip to content

Commit

Permalink
Remove the class keyword
Browse files Browse the repository at this point in the history
  • Loading branch information
brson committed Aug 17, 2012
1 parent 6d7b143 commit 3ab4b01
Show file tree
Hide file tree
Showing 143 changed files with 185 additions and 421 deletions.
170 changes: 7 additions & 163 deletions doc/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ The keywords in [source files](#source-files) are the following strings:
~~~~~~~~ {.keyword}
again assert
break
check class const copy
check const copy
drop
else enum export extern
fail false fn for
Expand All @@ -220,6 +220,7 @@ let log loop
match mod mut
pure
return
struct
true trait type
unchecked unsafe
while
Expand Down Expand Up @@ -1097,151 +1098,6 @@ enum list<T> {
let a: list<int> = cons(7, @cons(13, @nil));
~~~~

### Classes

A _class_ is a named record type that collects together fields and
methods. It must have a _constructor_ (a function called `new` that
returns a new instance of the class), and may have a destructor (a
nullary function called `drop` that executes before the memory manager
frees the memory for a given class). For historical reasons, we may
call a class with a destructor and a single field a "resource".

A _class item_ declares a class type:

~~~~
class file_descriptor {
let fd: libc::c_int;
new(fd: libc::c_int) { self.fd = fd; }
drop { libc::close(self.fd); }
}
~~~~

Calling the `file_descriptor` constructor function on an integer will
produce a value with the `file_descriptor` type.

_Fields_ are immutable by default, so instances of `file_descriptor`
can't have their `fd` fields reassigned. A mutable field declaration
looks like:

~~~~
let mut fd: libc::c_int;
~~~~

The only exception is that the body of the class constructor begins
with all the class's fields uninitialized, and is allowed to -- in
fact, must -- initialize all the fields. The compiler enforces this
invariant.

Usually, the class constructor stores its argument or arguments in the
class's named fields. In this case, the `file_descriptor`'s data field
would be accessed like `f.fd`, if `f` is a value of type
`file_descriptor`. By default, class fields are _public_: they can be
accessed both from methods inside the class, and code outside the
class. Classes can also have private fields:

~~~~
class file_descriptor {
let fd: *libc::FILE;
new(fd: *libc::FILE) {
self.fd = fd; self.name = none;
}
priv {
let mut name: option<~str>;
}
fn get_name() -> ~str {
match self.name {
none => fail ~"File has no name!",
some(n) => n
}
}
}
~~~~

Private fields are instance-private: methods in a class `C` can access
`self`'s private fields, but not private fields of other values of
type `C`. Code outside a class can't access any private fields.

A class item may contain _methods_, which take an implicit `self`
argument:

~~~~
class file_descriptor {
let fd: *libc::FILE;
new(fd: *libc::FILE) { self.fd = fd; }
fn flush() {
libc::fflush(self.fd);
}
}
~~~~

In this case, ```open``` is a nullary method that calls the
```fopen``` function, defined in another library, on the ```fd```
field. As in this example, methods must refer to their self's fields
as fields of ```self```; bare references to ```fd``` can't
occur. Methods can be public or private; just like fields, they are
public by default and private if enclosed in a `priv` section.

Classes may be polymorphic:

~~~~
class file<A: copy> {
let data: A;
let fd: *libc::FILE;
new(data: A, fd: *libc::FILE) { self.data = data; self.fd = fd; }
}
~~~~

Methods may also be polymorphic, and can have additional type
parameters other than those bound in the class:

~~~~
class file<A: copy> {
let data: A;
let fd: *libc::FILE;
new(fd: *libc::FILE, data: A) { self.fd = fd; self.data = data; }
fn map_data<B>(f: fn(A) -> B) -> B {
f(self.data)
}
}
~~~~

Classes do not support inheritance, except through traits. As a
result, all class method dispatch is static (non-virtual).

A class may implement a trait (see [traits](#traits)):

~~~~
trait to_str {
fn to_str() -> ~str;
}
class file : to_str {
let fd: *libc::FILE;
new(fd: *libc::FILE) { self.fd = fd; }
fn to_str() -> ~str { ~"a file" }
}
~~~~

The syntax `class file: to_str` is pronounced "class `file`
implements trait `to_str`".

Class instances may be allocated on the stack, in the exchange heap,
or on the task heap. A value with a class type ```C``` has a
noncopyable [type kind](#type-kinds) if ```C``` has a destructor, and
thus may not be copied. Class types that don't have destructors may be
copied if all their fields are copyable.

The semantics guarantee that for each constructed resource value, the
destructor will run once: when the value is disposed of (barring
drastic program termination that somehow prevents unwinding from
taking place). For stack-allocated values, disposal happens when the
value goes out of scope. For values in shared boxes, it happens when
the reference count of the box reaches zero.

The order of fields in a class instance is significant; its runtime
representation is the same as that of a record with identical fields
laid out in the same order.

### Traits

A _trait item_ describes a set of method types. [_implementation
Expand Down Expand Up @@ -1348,7 +1204,7 @@ trait. The methods in such an implementation can only be used
statically (as direct calls on the values of the type that the
implementation targets). In such an implementation, the `of` clause is
not given, and the name is mandatory. Such implementations are
limited to nominal types (enums, classes) and the implementation must
limited to nominal types (enums, structs) and the implementation must
appear in the same module or a sub-module as the receiver type.

_When_ a trait is specified, all methods declared as part of the
Expand Down Expand Up @@ -2744,9 +2600,9 @@ fn main() {
In this example, the trait `printable` occurs as a type in both the type signature of
`print`, and the cast expression in `main`.

### Class types
### Struct types

Every class item defines a type. See [classes](#classes).
Every struct item defines a type.

### Type parameters

Expand All @@ -2766,7 +2622,7 @@ type `~[B]`, a vector type with element type `B`.

### Self type

The special type `self` has a meaning within methods inside a class or
The special type `self` has a meaning within methods inside an
impl item. It refers to the type of the implicit `self` argument. For
example, in:

Expand All @@ -2781,19 +2637,7 @@ impl ~str: printable {
~~~~~~

`self` refers to the value of type `str` that is the receiver for a
call to the method `to_str`. Similarly, in a class declaration:

~~~~~~
class cat {
let mut meows: uint;
new() { self.meows = 0; }
fn meow() { self.meows = self.meows + 1; }
}
~~~~~~

`self` refers to the class instance that is the receiver of the method
(except in the constructor `new`, where `self` is the class instance
that the constructor implicitly returns).
call to the method `to_str`.

## Type kinds

Expand Down
79 changes: 0 additions & 79 deletions doc/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -1821,85 +1821,6 @@ fn contains(v: ~[int], elt: int) -> bool {

`for` syntax only works with stack closures.

# Classes

Rust lets users define new types with fields and methods, called 'classes', in
the style of object-oriented languages.

> ***Warning:*** Rust's classes are in the process of changing rapidly. Some more
> information about some of the potential changes is [here][classchanges].
[classchanges]: http://pcwalton.github.com/blog/2012/06/03/maximally-minimal-classes-for-rust/

An example of a class:

~~~~
class example {
let mut x: int;
let y: int;
priv {
let mut private_member: int;
fn private_method() {}
}
new(x: int) {
// Constructor
self.x = x;
self.y = 7;
self.private_member = 8;
}
fn a() {
io::println(~"a");
}
drop {
// Destructor
self.x = 0;
}
}
fn main() {
let x: example = example(1);
let y: @example = @example(2);
x.a();
x.x = 5;
}
~~~~

Fields and methods are declared just like functions and local variables, using
'fn' and 'let'. As usual, 'let mut' can be used to create mutable fields. At
minimum, Rust classes must have at least one field.

Rust classes must also have a constructor, and can optionally have a destructor
as well. The constructor and destructor are declared as shown in the example:
like methods named 'new' and 'drop', but without 'fn', and without arguments
for drop.

In the constructor, the compiler will enforce that all fields are initialized
before doing anything that might allow them to be accessed. This includes
returning from the constructor, calling any method on 'self', calling any
function with 'self' as an argument, or taking a reference to 'self'. Mutation
of immutable fields is possible only in the constructor, and only before doing
any of these things; afterwards it is an error.

Private fields and methods are declared as shown above, using a `priv { ... }`
block within the class. They are accessible only from within the same instance
of the same class. (For example, even from within class A, you cannot call
private methods, or access private fields, on other instances of class A; only
on `self`.) This accessibility restriction may change in the future.

As mentioned below, in the section on copying types, classes with destructors
are considered 'resource' types and are not copyable.

Declaring a class also declares its constructor as a function of the same name.
You can construct an instance of the class, as in the example, by calling that
function. The function and the type, though they have the same name, are
otherwise independent. As with other Rust types, you can use `@` or `~` to
construct a heap-allocated instance of a class, either shared or unique; just
call e.g. `@example(...)` as shown above.

# Argument passing

Rust datatypes are not trivial to copy (the way, for example,
Expand Down
4 changes: 2 additions & 2 deletions src/libcore/comm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ fn listen<T: send, U>(f: fn(Chan<T>) -> U) -> U {
f(po.chan())
}

class PortPtr<T:send> {
struct PortPtr<T:send> {
let po: *rust_port;
new(po: *rust_port) { self.po = po; }
drop unsafe {
Expand Down Expand Up @@ -132,7 +132,7 @@ class PortPtr<T:send> {
*/
fn as_raw_port<T: send, U>(ch: comm::Chan<T>, f: fn(*rust_port) -> U) -> U {

class PortRef {
struct PortRef {
let p: *rust_port;
new(p: *rust_port) { self.p = p; }
drop {
Expand Down
6 changes: 3 additions & 3 deletions src/libcore/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ impl<T: Reader, C> {base: T, cleanup: C}: Reader {
fn tell() -> uint { self.base.tell() }
}

class FILERes {
struct FILERes {
let f: *libc::FILE;
new(f: *libc::FILE) { self.f = f; }
drop { libc::fclose(self.f); }
Expand Down Expand Up @@ -415,7 +415,7 @@ impl fd_t: Writer {
}
}

class FdRes {
struct FdRes {
let fd: fd_t;
new(fd: fd_t) { self.fd = fd; }
drop { libc::close(self.fd); }
Expand Down Expand Up @@ -764,7 +764,7 @@ mod fsync {


// Artifacts that need to fsync on destruction
class Res<t> {
struct Res<t> {
let arg: Arg<t>;
new(-arg: Arg<t>) { self.arg <- arg; }
drop {
Expand Down
2 changes: 1 addition & 1 deletion src/libcore/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ fn test_unwrap_str() {

#[test]
fn test_unwrap_resource() {
class r {
struct r {
let i: @mut int;
new(i: @mut int) { self.i = i; }
drop { *(self.i) += 1; }
Expand Down
2 changes: 1 addition & 1 deletion src/libcore/priv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ unsafe fn weaken_task(f: fn(comm::Port<()>)) {
let _unweaken = Unweaken(ch);
f(po);

class Unweaken {
struct Unweaken {
let ch: comm::Chan<()>;
new(ch: comm::Chan<()>) { self.ch = ch; }
drop unsafe {
Expand Down
2 changes: 1 addition & 1 deletion src/libcore/rand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ impl Rng {

}

class RandRes {
struct RandRes {
let c: *rctx;
new(c: *rctx) { self.c = c; }
drop { rustrt::rand_free(self.c); }
Expand Down
2 changes: 1 addition & 1 deletion src/libcore/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ fn start_program(prog: &str, args: &[~str]) -> Program {
libc::fclose(r.out_file);
libc::fclose(r.err_file);
}
class ProgRes {
struct ProgRes {
let r: ProgRepr;
new(+r: ProgRepr) { self.r = r; }
drop { destroy_repr(&self.r); }
Expand Down
2 changes: 1 addition & 1 deletion src/libcore/stackwalk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import sys::size_of;

type Word = uint;

class Frame {
struct Frame {
let fp: *Word;

new(fp: *Word) {
Expand Down
Loading

0 comments on commit 3ab4b01

Please sign in to comment.