Newbie questions concerning match patterns

Hi! I've some questions concerning match patterns, I could not find the answers by googling, I hope they are not too stupid :smile:

So basically, to learn Rust I decided to write a (pseudo-) scheme interpreter and the core data structure is the Expr, so the idea was to have something like that (omitting a few variants for conciseness):

enum Expr {
  Nil;
  Integer(i64);
  Cons(Expr, Expr);
} 

Now obviously this doesn't work like that, the Expr in Cons must be a reference so the type can have a fixed size, I get that. I decided to use Rc for this, since a) a sub-expression can be referred by multiple expressions, so a Box would not be sufficient ; b) it's a toy project, no need to to worry about multithreading yet, so Rc is enough.

So in my final version I have this:

enum Expr {
  Nil;
  Integer(i64);
  Cons(Rc<Expr>, Rc<Expr>);
} 

and it works, but I feel like I might be missing something with how match works, because I end up having some ugly imbricated matches. E.g, when I want to check that the expression is a list of two elements and return them, I'd like to write something like this:

match expr {
  Cons(x, Cons(y, Nil)) => (x,y),
  _ => error()
}

Except, because of the Rc (?) I didn't manage to get something like this working, and end up with something like that, which isn't as pretty:

match expr {
  Expr::Cons(ref x, ref rest) =>
      match **rest { 
         Expr::Cons(ref y, Expr::Nil) => (x.clone(), y.clone()),
         _ => error()
      },
  _ => error()
}

So, time for my questions:

  1. why do I need to use namespace Expr::, and can I do something to get rid of those in match patterns to Expr? I mean, when I match on Option or Result I don't need to qualify their namespaces, so it must be possible?
  2. Is there a way to not have imbricated matches, even though the internal Expr is in a Rc? I tried putting some & and * in the match (a bit randomly in the end, I confess, I really don't have a clear model of how match works for complicated cases) but could not get anything to work...
1 Like

1: Enums are always name spaced like that to make sure they don't collide with other types (believe me, that was annoying back in the days), but you can always import them with use:

//Import only a few
use Expr::{Nil, Cons};

//Import everything
use Expr::*;

That is already done for Option and Result in the prelude, so that's why they can be used with only their variant names. You can do the imports within the function if you want to avoid polluting the name space.

2: The content of an Rc is not publicly available and I don't think you can match on it at the moment. I seem to recall someone mentioning something about the box pattern being usable for more than just Box in the future, but I have absolutely no information about that. Only hopes and wishes.

Thanks for your answer, it's a bit clearer now :slight_smile:

Box patterns
http://doc.rust-lang.org/stable/book/box-syntax-and-patterns.html

It's possible that it will, once stable, work for things like Rc too, yeah.

That would be incredibly helpful in cases like this :slight_smile: It's on my Rust wishlist.