Just An Application

July 8, 2013

Programming With Rust — Part Twenty: Where Have The Sockets Gone ? – Changes Between Rust 0.6 And Rust 0.7

One moment the socket functions were in the module std:net::tcp and the next moment they had gone.

A bit of an exaggeration, but between Rust 0.6 and 0.7 there have been a number of changes which affect the httpd code.

1.0 Std Is The New Core

The core crate has renamed to std and some modules that were in the previous version of the std crate in 0.6 have been moved elsewhere.

Like the core crate before it, it is not necessary to explicitly link to the std crate, but the visibility of some items has changed in the transition and in some cases explicit name bindings are now required.

The most obvious example affects the use of the function io::println.

In 0.6 it was possible to use it as is, in 0.7 it is now necessary to bind the io module name like this

    use std::io;

in files which use io::println.

2.0 The Extra Crate

The extra crate is the new home of some of the modules which had previously been in the std crate in 0.6.

In particular it is the new home of the net modules. So that is where the sockets have gone

3.0 Iterators

Rust is moving from iteration via closures to iteration via explicit iterators.

3.1 The Iterator Trait

The trait Iterator is defined in the module std::iterator.

It defines the method

    fn next(&mut self) -> Option<A>

which will look familiar to anybody who has progammed in Java.

3.2 The Changes

A number of functions/methods have either changed or disappeared entirely.

For example, the function

    fn each_word<'a>(s: &'a str, it: &fn(&'a str) -> bool)

defined in the str module has gone.

In its place is the method

    fn word_iter(&self) -> WordIterator<'self>

defined by the Str trait.

So

    fn readRequestLine(buffer: &mut RequestBuffer) -> (Method, RequestURI)
    {
        let     line           = buffer.readLine();
        let mut parts: ~[&str] = ~[];
        
        str::each_word(line, |part| { parts.push(part); true });
    
        if (vec::len(parts) != 3)
        {
            fail!(fmt!("Invalid status line: %s", line));
        }
    
        let method = Method::fromString(parts[0]);
        let uri    = RequestURI::fromString(method, parts[1]);
    
        (method, uri)
    }

in Rust 0.6, becomes

    fn readRequestLine(buffer: &mut RequestBuffer) -> (Method, RequestURI)
    {    
        let     line           = buffer.readLine();
        let mut parts: ~[&str] = ~[];
    
        for line.word_iter().advance |part| 
        {
            parts.push(part);
        }
        if (parts.len() != 3)
        {
            fail!(fmt!("Invalid status line: %s", line));
        }
    
        let method = Method::fromString(parts[0]);
        let uri    = RequestURI::fromString(method, parts[1]);

        (method, uri)
    }

in Rust 0.7

4.0 Lifetimes

The methods in httpd which return a borrowed pointer and consequently need to specify a lifetime for that pointer, for example,

    pub fn getURI(&self) -> &'self RequestURI
    {
        &self.uri
    }

no longer compile in Rust 0.7.

This change is not specifically mentioned in the release notes.

The solution is to parameterize the method in terms of the lifetime, like so

    pub fn getURI<'a>(&'a self) -> &'a RequestURI
    {
        &self.uri
    }

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.

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.

Create a free website or blog at WordPress.com.

%d bloggers like this: