Matthieu,

I tried to model something similar this way.  Sometimes the extra pattern 
matching gets tedious with this approach.  You also end up with a lot of 
constructors with similar names.  I also found myself  writing a lot of trivial 
function wrappers around constructors.  Of course there are benefits to a 
non-extensible system like this.  For instance, you can tell if you have 
addressed every case in a match statement.

Someone on IRC mentioned that a feature similar to Haskell pattern synonyms may 
make it less awkward to use these enum wrappers.

Eric

On Mar 13, 2014, at 12:56 PM, Matthieu Monrocq <matthieu.monr...@gmail.com> 
wrote:

> And of course I forgot to reply to the list at large... sorry :x
>  
> -- Matthieu
> 
> 
> On Wed, Mar 12, 2014 at 8:48 PM, Matthieu Monrocq 
> <matthieu.monr...@gmail.com> wrote:
> 
> 
> 
> On Tue, Mar 11, 2014 at 10:18 PM, Patrick Walton <pcwal...@mozilla.com> wrote:
> On 3/11/14 2:15 PM, Maciej Piechotka wrote:
> Could you elaborate on DOM? I saw it referred a few times but I haven't
> seen any details. I wrote simple bindings to libxml2 dom
> (https://github.com/uzytkownik/xml-rs - warning - I wrote it while I was
> learning ruby) and I don't think there was a problem of OO - main
> problem was mapping libxml memory management and rust's one [I gave up
> with namespaces but with native rust dom implementation it would be
> possible to solve in nicer way]. Of course - I might've been at too
> early stage.
> 
> You need:
> 
> 1. One-word pointers to each DOM node, not two. Every DOM node has 5 pointers 
> inside (parent, first child, last child, next sibling, previous sibling). 
> Using trait objects would 10 words, not 5 words, and would constitute a large 
> memory regression over current browser engines.
> 
> 2. Access to fields common to every instance of a trait without virtual 
> dispatch. Otherwise the browser will be at a significant performance 
> disadvantage relative to other engines.
> 
> 3. Downcasting and upcasting.
> 
> 4. Inheritance with the prefix property, to allow for (2).
> 
> If anyone has alternative proposals that handle these constraints that are 
> more orthogonal and are pleasant to use, then I'm happy to hear them. I'm 
> just saying that dismissing the feature out of hand is not productive.
> 
> 
> Patrick
> 
> 
> Please excuse me, I need some kind of visualization here, so I concocted a 
> simple tree:
> 
> // So, in pseudo C++, let's imagine a DOM tree
> struct Element { Element *parent, *prevSib, *nextSib, *firstChild, 
> *lastChild; uint leftPos, topPos, height, width; bool hidden; };
> struct Block: Element { BlockProperties blockP; }; struct Div: Block {};
> struct Inline: Element { InlineProperties inlineP; }; struct Span: Inline {};
> 
> 
> Now, I'll be basically mimicking the way LLVM structures its AST, since the 
> LLVM AST achieves dynamic casting without RTTI. Note that this has a very 
> specific downside: the hierarchy is NOT extensible.
> 
> // And now in Rust (excuse my poor syntax/errors)
> enum ElementChild<'r> { ChildBlock(&'r Block), ChildInline(&'r Inline) }
> 
> struct Element {
>     child: Option<&'self ElementChild<'self>>;
>     parent: &'self Element;
>     prevSib, nextSib, firstChild, lastChild: Option<&'self Element>;
>     leftPos, topPos, height, width: uint;
>     hidden: bool;
> }
> 
> 
> enum BlockChild<'r> { ChildDiv(&'r Div) }
> 
> struct Block {
>     elementBase: Element;
>     child: Option<&'self BlockChild<'self>>;
>     blockP: BlockProperties;
> }
> 
> struct Div { blockBase: Block; }
> 
> 
> enum InlineChild<'r> { ChildSpan(&'r Span) }
> 
> struct Inline {
>     elementBase: Element;
>     child: Option<&'self InlineChild<'self>>;
>     inlineP: InlineProperties;
> }
> 
> struct Span { inlineBase: Inline; }
> 
> 
> Let us review our objectives:
> 
> (1) One word to each DOM element: check => Option<&'r Element>
> 
> (2) Direct access to a field, without indirection: check => 
> span.inlineBase.elementBase.hidden
> 
> (3) Downcast and upcasting: check => downcast is done by matching: 
> match(element.child) { ChildBlock(&'r block) => /* act on block */, 
> ChildInline(&'r inline) => /* act on inline */); upcast is just accessing the 
> "base" field.
> 
> (4) Inheritance with the prefix property => not necessary, (2) is already 
> satisfied.
> 
> 
> Note on (3): multiple bases are allowed easily, it's one field per base.
> 
> 
> In order to reduce the foot-print; avoiding having a "child" field at each 
> level of the hierarchy might be beneficial. In this case, only the final 
> classes are considered in ElementChild
> 
> enum ElementChild<'r> { ChildDiv(&'r Div), ChildSpan(&'r Span) }
> 
> And then downcasting to &'r Block is achieved by:
> 
> match(element.final) { ChildDiv(&'r div) => Some(&'r div.blockBase), _ => 
> None }
> 
> 
> I would note that this does not make use of traits at all; the analysis is 
> only based on Patrick's list of objectives which I guess is incomplete and I 
> was lacking a realistic example so it might not address the full scope of the 
> problem...
> 
> ... still, for CLOSED hierarchies, the use of traits should not be necessary, 
> although it might be very convenient.
> 
> -- Matthieu.
>  
> _______________________________________________
> Rust-dev mailing list
> Rust-dev@mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev
> 
> 
> _______________________________________________
> Rust-dev mailing list
> Rust-dev@mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev

_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to