[rust-dev] Questions about rust's OO.

Brian Anderson banderson at mozilla.com
Mon Aug 27 13:53:53 PDT 2012


On 08/26/2012 07:25 PM, Steve Jenson wrote:
> On Sun, Aug 26, 2012 at 6:45 PM, Tim Chevalier <catamorphism at gmail.com> wrote:
>> On Sun, Aug 26, 2012 at 6:33 PM, Steve Jenson <stevej at fruitless.org> wrote:
>>> Hi rustics,
>>>
>>> I spent some time this weekend going over the rust tutorial and
>>> documentation for 0.3.1. I thought a fun exercise would be writing an
>>> xUnit testing framework[1] in a "classic" OO style. I ran into a few
>>> problems:
>>>
>>> 1) xUnit historically relies on inheritance but it's not clear to me
>>> how to model an is-a relationship in Rust. For instance, define an
>>> abstract base class (TestSuite) and an implementation that tests a set
>>> of functions (say, a calculator).
>>>
>>
>> Hi, Steve --
>>
>> The way to do this in Rust would be to define a trait TestSuite, and
>> impls that implement that trait for various types. Patrick's tutorial
>> should be helpful:
>>
>> http://pcwalton.github.com/blog/2012/08/08/a-gentle-introduction-to-traits-in-rust/
>
> Based on that, I came up with a super naive attempt. I realize this is
> basically trying to write Java in rust so I apologize in advance.
>
> trait TestSuite {
>      fn setup();
>      fn teardown();
> }
>
> struct Calculator {
>      fn add(m: int, n: int) -> int {
>          return m + n;
>      }
> }
>
> impl CalculatorTest : TestSuite { // error: use of undeclared type
> name `CalculatorTest`
>      // without this, I have nothing to call
>      //let calculator = Calculator();
>
>      fn setup() {}
>      fn teardown() {}
>
>      fn test_addition() -> bool {
>          return true;
>      }
> }
>

This is closer to working code in current Rust:

// The type we want to test
struct Calculator {
   need_at_least_one_field: (); // per a compiler limitation
}

// Methods on our type
impl Calculator {
   fn add(m: int, n: int) -> int { ... }
}

// The type of a test suite
trait TestSuite {
   fn startup();
   fn teardown();
}

// Our test suite
struct CalculatorTest {
   mut calculator: Option<Calculator>;
}

impl CalculatorTest: TestSuite {

   fn startup() {
     self.calculator = Some(Calculator {
       need_at_least_one_field: ();
     });
   }

   fn teardown() { /* nop */ }

   fn test() {
     assert self.calculator.is_some();
   }

}

// The test suite constructor
fn CalculatorTest() -> CalculatorTest {
   CalculatorTest {
     calculator: None
   }
}

> Based on my experience in Haskell, there's a number of ways I could
> tackle this problem but I think it's safe to say that most people who
> think of themselves as 'systems programmers' would attempt the above
> first and wonder why rust's OO is 'weird'?
>
> I'm also curious what a rust-oriented solution to this problem would look like.
>
>>> 2) How to colocate state and behavior in impls. Embedding lets in my
>>> impls results in errors.
>>
>> impls don't talk about state, and we don't have plans to change that
>> as far as I know. As shown in Patrick's tutorial, you define all your
>> fields in struct definitions, and then provide impls that implement
>> various traits for a particular struct. This doesn't preclude
>> anything: you can always define methods on a struct that get/set its
>> fields.
>>
>>>
>>> 3) Reflection. I have no documented way to iterate over the functions
>>> in an impl and call them. (I'm sure this is on the way and I'm just
>>> early to the party)
>>>
>>
>> I don't know of any plans to do this. I'm not sure why you would want
>> to; if you can give an example, it might help.
>
> In a traditional xUnit framework, your test suite subclasses have
> methods that are prefixed with 'test' and you use reflection to
> iterate over the methods and call each method whose name starts with
> 'test', calling setup() and teardown() around each invocation.
>
> In a BDD framework, you build tests as anonymous functions and you can
> register them and call them without resorting to reflection. In rust,
> this would look something like:
>
> describe('add two numbers', fun () -> bool { assertEqual(calc.add(1, 1), 2) });

This would read well in Rust:

do describe("add two numbers") {
   assert calc.add(1, 1) == 2;
}

>
>>> I also think I'm approaching this from the wrong direction and that
>>> Rust's OO with typeclasses are different from how I'm using to
>>> building software in another language with typeclasses (Scala). I'm
>>> still looking for the zen of Rust OO.
>>>
>>> I ran into some old blog posts that discuss a class keyword but I
>>> wasn't able to make those examples run in 0.3.1. Do we only have impls
>>> now?
>>
>> The class keyword is deprecated; struct replaces class.
>>
>> Feel free to ask again if you have more questions (or visit #rust on IRC).
>
> Thanks again! I hope this is helpful and doesn't seem like I'm trolling.
>
> steve
> _______________________________________________
> Rust-dev mailing list
> Rust-dev at mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev
>



More information about the Rust-dev mailing list