1 / 77

ConceptClang : An Implementation Model for C++ Concepts – An Update

ConceptClang : An Implementation Model for C++ Concepts – An Update. Larisse Voufo Center for Research in Extreme Scale Technologies (CREST) Indiana University Adrian Kothman , Maxwell Crouse CS Undergraduate Mentees PL-Wonks, November 2013. Topics. Generic programming with concepts

gaius
Download Presentation

ConceptClang : An Implementation Model for C++ Concepts – An Update

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. ConceptClang: An Implementation Model for C++ Concepts – An Update Larisse Voufo Center for Research in Extreme Scale Technologies (CREST) Indiana University Adrian Kothman, Maxwell Crouse CS Undergraduate Mentees PL-Wonks, November 2013

  2. Topics • Generic programming with concepts • in C++. • Implementing concepts with ConceptClang • for C++, • in Clang. • in other compilers? • for other languages? • e.g. Chapel? • Talk to Max and Adrian.

  3. Topics • Generic programming with concepts • in C++. • Implementing concepts with ConceptClang • for C++, • for other languages? • e.g. Chapel? • Ongoing theoretical findings: • Name binding framework: • Clarifies complex rules like argument-dependent lookup (ADL) in C++. • Introduces a new scoping rule: weak hiding. • Specifies a new mechanism: two-stage name binding. • Open classes (extensible structures) for free.

  4. Outline • Brief Introduction: • Generic programming with concepts. • Constrained C++ templates. • Implementing concepts w/ ConceptClang. • Ongoing theoretical findings: • Name binding framework. • Open classes (extensible structures) for free. • ConceptClang’edChapel, an ongoing undergraduate project. • https://github.iu.edu/lvoufo/CCedChapel[branch:mvcrouse]

  5. Generic Programming • Different languages support it in various capacities: Genericity by … • Value: e.g. function abstraction • Type: e.g. (parametric or adhoc) polymorphism • Function: e.g. functions as values • Structure: e.g. requirements and operations on types • Property: e.g. properties on type • Stage: e.g. meta-programming • Shape: e.g. datatype-generic cf. "Datatype Generic Programming”. Gibbons. [In Spring School on Datatype-Generic Programming, volume 4719 of Lecture Notes in Computer Science. Springer-Verlag.] • C++ supports generic programming via templates.

  6. Generic Programming w/ Concepts • Different languages support it in various capacities: Genericity by … • Value: e.g. function abstraction • Type: e.g. (parametric or adhoc) polymorphism • Function: e.g. functions as values • Structure: e.g. requirements and operations on types • Property: e.g. properties on type • Stage: e.g. meta-programming • Shape: e.g. datatype-generic cf. "Datatype Generic Programming”. Gibbons. [In Spring School on Datatype-Generic Programming, volume 4719 of Lecture Notes in Computer Science. Springer-Verlag.] • C++ supports generic programming via constrained templates.

  7. Example: Lifting template<InputIterator I, typenameT, BinaryFunction Op> requires(Assignable<InputIterator<I>::value_type, BinaryFunction<Op>::result_type>) Taccumulate(I first, I last, Tinit, Opbin_op) { for (; first != last; ++first) init = bin_op(init, *first); return init; } accumulate(arr, arr+3, 0, 1) int sum(int* array, int n) { int s = 0; for (inti = 0; i < n; ++i) s = s + array[i]; return s; } Same Complexity. sum(arr,3)

  8. Example: Requirements Grouping concept InputIterator<typename X> : Iterator<X>,EqualityComparable<X>{ ObjectTypevalue_type = typename X::value_type; MoveConstructible pointer = typename X::pointer; SignedIntegralLikedifference_type = typename X::difference_type; ... pointer operator->(const X&); };

  9. C++ Templates • C++ supports generic programming via templates. • Templates alone are not expressive enough, nor safe: • Too general. • Lengthy and obscure error messages. • Encapsulation breakage. • Primarily used by experts. • “Tricks” are even more complex to understand. • Worse: semantic errors go undetected.

  10. Example 1: Error Detection and Diagnosis with C++ Templates vector<void*> v; sort(v.begin(), v.end(), boost::bind(less<int>(),_1,_2)); $ clang++ test.cpp -o example /usr/local/include/boost/bind/bind.hpp:303:16: error: no matching function for call to object of type 'std::less<int>' return unwrapper<F>::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_]); ^~~~~~~~~~~~~~~~~~~~~~~~~~ /usr/local/include/boost/bind/bind_template.hpp:61:27: note: in instantiation of function template specialization 'boost::_bi::list2<boost::arg<1>, boost::arg<2> >::operator()<bool, std::less<int>, boost::_bi::list2<void *&, void *&> >' requested here BOOST_BIND_RETURN l_(type<result_type>(), f_, a, 0); ^ /usr/include/c++/4.2.1/bits/stl_algo.h:2501:6: note: in instantiation of function template specialization 'boost::_bi::bind_t<boost::_bi::unspecified, std::less<int>, boost::_bi::list2<boost::arg<1>, boost::arg<2> > >::operator()<void *, void *>' requested here if (__comp(*__i, *__first)) ^ /usr/include/c++/4.2.1/bits/stl_algo.h:2591:7: note: in instantiation of function template ... 2 errors generated. Incompatible Binary Operator!

  11. Example 2: Error Detection and Diagnosis with C++ Templates vector<int> v; sort(v.begin(), v.end(), not_equal_to<int>()); $ clang++ test.cpp -o example $ (None !?) Not Valid Ordering!

  12. Example 1: Error Detection and Diagnosis with Constrained Templates vector<void*> v; constrained_sort(v.begin(), v.end(), boost::bind(less<int>(),_1,_2)); $ clang++ test.cpp -o example test.cpp:260:2: error: no matching function for call to 'constrained_sort' constrained_sort(v.begin(), v.end(), boost::bind(less<int>(), _1, _2)); ^~~~~~~~~~~~~~~~ ./constrained_algo.h:39:6: note: candidate template ignored: constraints check failure [with I = __gnu_cxx::__normal_iterator<void **, std::vector<void *, std::allocator<void *> > >, Cmp= boost::_bi::bind_t<boost::_bi::unspecified, std::less<int>, boost::_bi::list2<boost::arg<1>, boost::arg<2> > >] void constrained_sort(I first, I last, Cmpbin_op) { ^ ./constrained_algo.h:38:17: note: Concept map requirement not met. Assignable<RandomAccessIterator<I>::value_type, ... ^ ./constrained_algo.h:37:3: note: Constraints Check Failed: constrained_sort. requires(RandomAccessIterator<I>, StrictWeakOrdering<Cmp>, ^ 1 error generated.

  13. Example 2: Error Detection and Diagnosis with Constrained Templates vector<int> v; constrained_sort(v.begin(), v.end(), not_equal_to<int>()); $ clang++ test.cpp -o example test.cpp:261:2: error: no matching function for call to 'constrained_sort' constrained_sort(v.begin(), v.end(), not_equal_to<int>()); ^~~~~~~~~~~~~~~~ ./constrained_algo.h:39:6: note: candidate template ignored: constraints check failure [with I = __gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >, Cmp = std::not_equal_to<int>] void constrained_sort(I first, I last, Cmpbin_op) { ^ ./constrained_algo.h:37:55: note: Concept map requirement not met. requires(RandomAccessIterator<I>, StrictWeakOrdering<Cmp>, ^ ./constrained_algo.h:37:3: note: Constraints Check Failed: constrained_sort. requires(RandomAccessIterator<I>, StrictWeakOrdering<Cmp>, ^ 1 error generated.

  14. Templates: Compiler Mechanism PARSING INSTANTIATION int accumulate (vector<int>::iterator first, vector<int>::iterator last, int init, plus<int> bin_op) { ...} template<typename Iter, typename T, typename BinOp> T accumulate(…) { …} Check Once! vector<int> v; int i = accumulate(v.begin(), v.end(), 0, plus<int>()); vector<int> v; int i = accumulate<vector<int>::iterator, int, plus<int> > (v.begin(), v.end(), 0, plus<int>()); int accumulate(vector<int>::iterator first, vector<int>::iterator last, int init, plus<int> bin_op); Template Definition: Template Use: Code Generation: Specialization:

  15. Constrained Templates: Mechanism PARSING INSTANTIATION int accumulate (vector<int>::iterator first, vector<int>::iterator last, int init, plus<int> bin_op) { ...} template<typenameI, typenameT, typename BinOp> requires(InputIterator<I>, BinaryFunction<Op>, ...) T accumulate(...) { ... } Check Constraints-Check Once! vector<int> v; int i = accumulate<vector<int>::iterator, int, plus<int> > (v.begin(), v.end(), 0, plus<int>()); int accumulate(vector<int>::iterator first, vector<int>::iterator last, int init, plus<int> bin_op); InputIterator<vector<int>::iterator>, BinaryFunction<bin_op>, ... Constrained Template Definition: Constrained Template Use: Code Generation: Specialization + Models:

  16. Concepts: Elementary Components • Concept Definition: • Name + parameters • Requirements • Refinements • Extends requirements • Constrained Template Definition: • Constraints specification • Concept Model (Template): • Concept id: name + arguments • Requirement satisfactions • Refinement satisfactions • One for each refinement • Constrained Template Use: • Constraints satisfaction

  17. ConceptClang extensions affect only 4/~17 components of Clang: The Driver component is modified only for compiler flags support. So, we do not consider it in our analysis. ConceptClang Infrastructure

  18. ConceptClang extensions affect only 4/~17 components of Clang: The Driver component is modified only for compiler flags support. So, we do not consider it in our analysis. ConceptClang Infrastructure See C++Now’12 Talk: “ConceptClang: Towards an Implementation Models for C++ Concepts”

  19. Preliminary Observation • The ConceptClang infrastructure is parameterized by the (type of) associated requirements. • E.g. declarations in PF, expressions in PA, • Statements in Chapel… • Main workload is at the infrastructure layer, in Sema: • constraints satisfaction, • concept model lookup, checking, generating, • name rebinding at instantiation time. • So far, only simple name uses, e.g., function calls, are covered. • In PF, thus also simple associated declarations and types.

  20. Current Limitations • In constrained generic components: Type-checking name uses  weak hiding and Two-Stage Name Binding. • Beyond simple function calls: Generalizing name uses ( or Two-Stage Name Binding)  structure-opening archetypes  Open/Extensible classes/structures for free.

  21. Outline • Brief Introduction: • Generic programming with concepts. • Constrained C++ templates. • Implementing concepts w/ ConceptClang. • Ongoing theoretical findings: • Name binding framework. • Open classes (extensible structures) for free. • ConceptClang’edChapel, an ongoing undergraduate project. • https://github.iu.edu/lvoufo/CCedChapel [branch:mvcrouse]

  22. Current Design Limitations • No good solution, presently. • Our name binding framework explains. :: concept Foo2<typename P> = requires (P a, P b) { foo(a, b); } void foo(int) { } template<Foo2T> void gen_func(T a, T b) { foo(a, b); foo(1); } Should Foo2<T>::foo() shadow ::foo()? How? Foo2<T> Reject or accept the call foo(1)?

  23. Our Name Binding Framework • Specifies name binding. :: void foo(); namespace adl { struct X {}; void foo(X); } namespace ns { void foo(int); } void test(adl::X x) { using ns::foo; foo(x); } adl ns test • Best viable candidate, or • error Bind

  24. Our Name Binding Framework • Specifies name binding, independently of the language. • Identify and combine scopes. :: void foo(); namespace adl { struct X {}; void foo(X); } namespace ns { void foo(int); } void test(adl::X x) { using ns::foo; foo(x); } • Execute generic name binding. adl ns test • Best viable candidate, or • error Bind

  25. Our Name Binding Framework • Specifies name binding, independently of the language. • Express scoping rules. :: void foo(); namespace adl { struct X {}; void foo(X); } namespace ns { void foo(int); } void test(adl::X x) { using ns::foo; foo(x); } • Apply scoping rules. adl ns test • Best viable candidate, or • error Bind

  26. Our Name Binding Framework • Specifies name binding, independently of the language. Use scope combinators. :: void foo(); namespace adl { struct X {}; void foo(X); } namespace ns { void foo(int); } void test(adl::X x) { using ns::foo; foo(x); } • Identify name binding on an elementary scope (generic). adl ns test • Best viable candidate, or • error Bind

  27. Our Name Binding Framework • Specifies name binding, independently of the language. Use scope combinators. :: void foo(); namespace adl { struct X {}; void foo(X); } namespace ns { void foo(int); } void test(adl::X x) { using ns::foo; foo(x); } • Depends on a Language concept. adl ns test • Best viable candidate, or • error Bind

  28. Our Name Binding Framework • Specifies name binding, independently of the language. Use scope combinators. :: void foo(); namespace adl { struct X {}; void foo(X); } namespace ns { void foo(int); } void test(adl::X x) { using ns::foo; foo(x); } • Instantiate the Languageconcept. adl ns test • Best viable candidate, or • error Bind

  29. Our Name Binding Framework • Abstracts from declarations, references, and scopes. void foo(); namespace adl { struct X {}; void foo(X); } namespace ns { void foo(int); } void test(adl::X x) { using ns::foo; foo(x); } • Scopes as maps of references to sets of matching declarations. • Best viable candidate, or • error Bind

  30. Our Name Binding Framework • Views name binding as composed of name lookup and resolution. • Name lookup returns the set of matching declarations, for a given reference. void foo(); namespace adl { struct X {}; void foo(X); } namespace ns { void foo(int); } void test(adl::X x) { using ns::foo; foo(x); } • Best viable candidate, or • error Bind

  31. Expressing Scoping Rules Use scope combinators. :: void foo(); namespace adl { struct X {}; void foo(X); } namespace ns { void foo(int); } void test(adl::X x) { using ns::foo; foo(x); } • Instantiate the Languageconcept. adl ns test • Best viable candidate, or • error Bind

  32. The Combinators • Hiding: • Commonly known as “shadowing”. • Merging: • Usuallythe alternative option to “shadowing”. • Opening: • [New name] Necessary to describe ADL. • A dual of hiding. • Weak Hiding: • [New rule] Necessary for (C++) concepts. • A sweet middle between hiding and merging.

  33. The HidingCombinator() void foo(); void test() { foo(); } :: Result: Binds foo() to ::foo(). test

  34. The MergingCombinator( ) void foo(); namespace ns{ void foo(int); } void test() { using ns::foo; foo(); } :: ns Result: Finds ns::foo(); Fails to bind foo(). test

  35. The Weak HidingCombinator( ) void foo(); namespace ns{ void foo(int); } void test() { using ns::foo; foo(); } :: ns Result: Binds foo() to ::foo(). test

  36. The OpeningCombinator() void foo(); namespace ns{ void foo(int); } namespace adl { struct X{}; void foo(typ); } void test(adl::Xx) { using ns::foo; foo(x); } :: ns Result: Finds ns::foo(); Enables ADL; Binds foo(x)to adl::foo(). adl test

  37. The OpeningCombinator() void foo(); namespace ns { void foo(int); } namespace adl{ struct X {}; void foo(typ); } void test(adl::Xx) { using ns::foo; void foo(); foo(x); } :: ns Result: Finds test::foo(); Disables ADL; Fails to bind foo(x). adl test

  38. Applications • Understanding current name binding mechanisms: • Argument-dependent lookup (ADL). • C++ operators. • A cross-language analysis. • Exploring concepts designs • Understanding the current limitations. • Exploring new solutions: • weak hiding, • 2-Stage name binding, and • parameterized weak hiding. • Simplifying compiler designs.

  39. C++ Operators Example structX{}; structY {}; void operator+(X, X) { } void operator+(X, Y) { } void test(X x, Y y) { void operator+(X, X); x + x; x + y; operator+(x, x); operator+(x, y); } test ::

  40. C++ Operators Scoping Ruleswithout ADL

  41. C++ Operators Scoping Ruleswith ADL Empty, since operator is a reserved keyword.

  42. C++ Operators Scoping Ruleswith ADL

  43. C++ Operators Scoping Ruleswith ADL

  44. Problem: Current Limitations • Current scoping rules break seemingly valid codes. :: concept Foo2<typename P> = requires (P a, P b) { foo(a, b); } void foo(int) { } template<Foo2T> void gen_func(T a, T b) { foo(a, b); foo(1); } Should Foo2<T>::foo() shadow ::foo()? How? Foo2<T> Reject or accept the call foo(1)?

  45. Solution: Weak Hiding :: concept Foo2<typename P> = requires (P a, P b) { foo(a, b); } void foo(int) { } template<Foo2T> void gen_func(T a, T b) { foo(a, b); foo(1); } Foo2<T>::foo() should weakly hide ::foo()! Foo2<T> Accept the call foo(1)!

  46. The Weak Hiding Scoping Rule concept Foo2<typename P> = requires (P a, P b) { …} void foo(int) { } template<Foo2T> void gen_func(T a, T b) { foo(a, b); foo(1); } Result: Binds foo() to ::foo(). Concept<T> ::

  47. Implementing Weak Hiding • Implementation = Two-Stage Name Binding (Bindx2) • Bind with inner scope: s1. • Bind with outer scope:s2. • Bindx2 repeats name binding under different contexts.

  48. Bindx2 for C++ Concepts • Within restricted scope: • up to the outermost restricted scope. • Disables ADL and some qualified name lookups. • In surrounding scope: • normal lookup – including ADL. concept Foo2<typename P> = requires (P a, P b) { …} void foo(int) { } template<Foo2T> void gen_func(T a, T b) { foo(a, b); foo(1); } Foo2<T> ::

  49. Ambiguity for C++ Concepts:What is the most desirable? Rejects desirable, or binds to undesirable • Ambiguity IS an error, always? • Ambiguity IS NOT an error, always? • A middle ground option? Accepts undesirable concept Foo2<typename P> { void foo(P, int); void foo(int, P); } template<Foo2 T> void gen_func(T a, int b) { foo(b, b);foo(b); } Proposed Extension: Accept only desirable! (?)

  50. Ambiguity for C++ Concepts:What is the most desirable? Rejects desirable, or binds to undesirable • Ambiguity IS an error, always? • Ambiguity IS NOT an error, always? • A middle ground option? See C++Now’13 Talk: “Weak Hiding for C++ Concepts and a Generic Way to Understand Name Binding.” Accepts undesirable concept Foo2<typename P> { void foo(P, int); void foo(int, P); } template<Foo2 T> void gen_func(T a, int b) { foo(b, b);foo(b); } Proposed Extension: Accept only desirable! (?)

More Related