
On Mon, Sep 27, 2010 at 10:31 AM, Eric Niebler <eric@boostpro.com> wrote:
On 9/26/2010 9:44 PM, David Abrahams wrote:
Meaning? Spell it out and you have your requirements.
Meaning:
+ If the topmost node has tag-type "plus", there must be exactly one child node that models SpiritParser + If the topmost node has tag-type "shift_right", there must be exactly two child nodes that model SpiritParser, + If the topmost node has tag-type "subscript", there must be a left node that models SpiritParser and a right node that models PhoenixLambda, ... etc, etc, etc, ad nauseum
How do I express that as a concept?
This is an interesting question. At first reading through this discussion, I was on the side of Dave thinking that "yes, why don't you just define a SpiritParser concept?" until I thought about it a little more. The way concepts are done now is to define the syntactic requirements (not so much the semantics) of what you require for a type. That means, that certain syntactic constructs be defined at the point of checking the concept (i.e. at compile time). In the case of a SpiritParser, I can see that there are really no syntactic requirements that you can require on each parser -- and although you can make a hierarchy of these concepts by refining a general SpiritParser concept, that only shows what you syntactically require of the type. Statements like: "The type T models a SpiritParser concept if T models DefaultConstructible, Assignable, and Swappable and also supports the following constructs: ``T t; t.foo(); t.bar();``" Can easily be accommodated by the current Boost.Concept_check library. I should know, I use it a lot of times to enforce structural/syntactic concept requirements. What's unique in the situation of Proto/Spirit is that they deal with compile-time constructs (syntax trees, expression templates) that can only be introspected by another compile-time construct (proto transforms, proto verify, MPL, etc.). What's missing in this case is a generic means of expressing tree structures, which complements the syntactic enforcement of requirements using Boost.Concept_check. Somehow I think this either has to be two things: 1. A compiler or extension to the language which allows for defining patterns and type enforcement for compile-time constructs. In Haskell there are Type Classes which are very similar to (the now defunct) C++ Concepts, but Type Classes allowed for the same (stratospheric) level of introspection at compilation time. This means Type Classes can themselves be used as definitions for enforcing the type of (or the *pattern* of, which is basically deduced anyway most of the time) a given function or data type. 2. A meta-meta programming language that allows for defining rules that enforce DSEL/EDSL grammars at compilation time. Although with C++ we are pretty much stuck with more template voodoo if we attempt to formalize something like this. Right now, Proto is a meta-EDSL -- I'm not sure if using just Proto to enforce the rules on Proto-based languages might be a sufficient solution if the aim is to make better compiler messages and/or for simplifying the user experience. Although right now, defining grammars using Proto also allows you to define transformations and even verifications to enforce the grammar, somehow either we need to have Proto Concepts to define tree patterns and valid globbings of Proto trees together that also somehow emit pretty compiler messages. #1 seems to require more man-years of work compared to #2, although #2 will require highly evolved and sufficiently capable template programming compilers.
Not necessarily. Concepts are not about expressing arbitrary template constraints. They're about describing abstractions. One might say that if you can't figure out how to write a concept for a template parameter, you don't understand the abstraction it's modelling.
I understand the abstraction perfectly well. It's a strongly-typed tree that conforms to a grammar. I haven't a clue how to express that as a concept. It's not a reflection of my poor understanding of my abstraction. It reflects my poor understanding of concepts. I'm sincerely asking for help trying to understand this.
If you can somehow transform the meaning of "strongly-typed tree" into a description that the compiler can enforce (similar to how you can require a member method "foo" with 0 arguments on a type T that supposedly models a concept Foo) then I think you have yourself an enforceable concept using Boost.Concept_check. Otherwise, you might have to make one for Proto to enforce not just grammar for the DSELs but also the concepts these strongly-typed trees are supposed to model. I can think of a Spirit Concept such as "SequenceParser" which can have as children a general "Parser", which has many refinements that can be checked by Proto, but only if Proto allowed for a means to define "SequenceParser" and "Parser" suitably as a Tree Pattern or generally a Concept that it itself (Proto) also enforces alongside the Grammar. I'll have to think a little bit more of how this might be achievable with just Boost.Concept_check. HTH and I really hope I made sense. :D -- Dean Michael Berris deanberris.com