Boost logo

Boost :

Subject: Re: [boost] [guidelines] why template errors suck
From: Dean Michael Berris (mikhailberis_at_[hidden])
Date: 2010-09-26 23:40:31


On Mon, Sep 27, 2010 at 10:31 AM, Eric Niebler <eric_at_[hidden]> 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

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk