Just An Application

July 8, 2013

Programming With Rust — Part Nineteen: Just One More Thing – Traits

1.0 Traits

A Rust Trait item defines an abstract type in terms of a set of methods.

For example

    trait Alchemist
    {
        fn transmutate(&self, baseMetal: Lead) -> Gold;
    }

defines the trait Alchemist.

The method transmutate can be called on the value of any type that has the trait Alchemist.

In its basic guise a Rust trait is very similar to a Java interface.

Traits also support inheritance like Java Interfaces but unlike them traits support static methods and default implementations of methods.[1]

2.0 Trait Implementation

The implementation of a trait for a given type is defined using a variant of the implementation item.

For example,

    impl Alchemist for NuclearReactor
    {
        fn transmutate(&self, baseMetal: Lead) -> Gold
        {
            bombardWithNeutronsAndOtherStuff(baseMetal)
        }
    }

defines the implementation of the trait Alchemist for the type NuclearReactor.

3.0 Object Types

The abstract type defined by a trait item is an object type.

A pointer to value of a type which implements a trait, e.g., ~NuclearReactor, is not automatically a pointer to a value of the object type defined by that trait, i.e., ~Alchemist.

In other words, you cannot do this

    let alchemist: ~Alchemist = ~NuclearReactor;

To obtain a pointer to a value of the object type defined by the trait from a pointer to value of a type which implements that trait,
you must explicitly cast it, for example

    let alchemist: ~Alchemist = ~NuclearReactor as ~Alchemist;

4.0 Default Methods

The Rust Reference Manual states that

Traits can include default implementations of methods

However, if you attempt to compile something like this

    trait TraitWithDefaultMethod
    {
        fn notVeryUsefulDefaultMethod(&self, x: uint) -> uint
        {
            x
        }
    
        fn notVeryUsefulMethod(&self);
    }

    struct AStruct;

    impl TraitWithDefaultMethod for AStruct
    {
        fn notVeryUsefulMethod(&self)
        {
        }
    }

    fn main()
    {

        let twdm = ~AStruct as ~TraitWithDefaultMethod;
    
        twdm.notVeryUsefulDefaultMethod(1203);

    }

you will get this

    ... error: default methods are experimental

Support for default methods can be enabled using the -A flag, like this

    rustc -A default_methods crate-file

which, when attempting to compile the code above, gets you this

    error: internal compiler error: unexpected failure

which is a bit unfortunate.

Update

In the all new Rust 0.7 which has just been released default methods remain experimental but the above code now compiles and runs, which is nice.

Notes

  1. Work being done as part of JSR 335: Lambda Expressions for the Java Programming Language will result in Java interfaces also supporting default methods and static methods.


Copyright (c) 2013 By Simon Lewis. All Rights Reserved.

Unauthorized use and/or duplication of this material without express and written permission from this blog's author and owner Simon Lewis is strictly prohibited.

Excerpts and links may be used, provided that full and clear credit is given to Simon Lewis and justanapplication.wordpress.com with appropriate and specific direction to the original content.

Blog at WordPress.com.

%d bloggers like this: