Reviving an old thread here because I'm still working on this.
I suspect you'll want to make a trait `Spanned` that the various
spanned-types implement, such that code that generically acts on "Some
spanned thing" can continue to work. Not sure, just a hunch.
I thought so too, but after removing spanned<T> from a few types I have not encountered the need to do so so far. The reason is probably that without traits a common abstraction over 'everthing having a span' couldn't be expressed, so no code was written that would rely upon such an abstraction.

(spanned<T> predates having traits at all, so if there's a better way to
approach this in current idioms, go right ahead)
It turns out that my initial reasoning for getting rid of spanned<T> didn't take enums properly into account. For these, having a wrapper containing data common to all variants makes more sense than for structs. Because otherwise the common fields have to be put in every variants:

struct spanned<T> {
span: span,
node: T
}

// This might be more convenient to use...
pub type decl = spanned<decl_>;

pub enum decl_ {
    decl_local(@Local),
    decl_item(@item),
}

// .. than this:
pub enum decl {
    decl_local(@Local, span),
    decl_item(@item, span),
}

Especially when the enum an has many variants (such as `ast::expr_` with 33 variants) adding a `span` field to all of them is kind of annoying. Apart from spanned<T> there are quite a few such wrapper structs containing common fields: ast::expr, ast::pat, ast::foreign_item, ast::item, ast::view_item, and ast::Ty to name only those in libsyntax/ast.rs

To me this seems very much like a slightly clunky way of emulating inheritance (with a lot more typing involved at definition and usage sites). Field accessor functions or traits can alleviate some of this clunkyness at the usage site; however, at the cost of even more boilerplate needed at the definition site:

pub enum decl {
    decl_local(@Local, span),
    decl_item(@item, span),
}

impl decl {
    fn get_span(&self) {
// this match statement also introduces some unnecessary runtime overhead...
        match *self {
            decl_local(_, span) => span,
            decl_item(_, span) => span
}
    }
}

This situation is not very satisfactory but I don't know an easy solution to the problem. I certainly don't suggest adding such a heavy tool as inheritance to Rust just for this use case.

So for now I'll keep adapting things to the new naming convention but I'll leave wrapped enums as they are. I'm very much interested in any comments regarding this problem of types with some common fields and some specialized fields. Type specialization is something popping up all the time and Rust seems to have some weak spots there.

Some concrete style questions:
- Do enum variants follow the guideline for variable_naming or TypeNaming. (Although, imo enum variants should be *subtypes* of their defining enum anyway ;) - What is the preferred naming convention for getter functions such as `get_span()` above? get_span()? just span()? something else?

Thanks for reading!
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to