Topic: [c++std-ext-16677] An implementation of


Author: David Vandevoorde <daveed@edg.com>
Date: Wed, 1 Apr 2015 09:11:55 -0400
Raw View
> On Apr 1, 2015, at 8:01 AM, Faisal Vali <faisalv@gmail.com> wrote:
>
> While I was fixing a bug in the constexpr-lambda branch - it occurred
> to me that true compile time closures -- i.e.constexpr lambdas that
> capture variables by reference, capture their relevant data-frames on
> the call stack, but only if executed at compile time) --  are
> relatively straightforward to implement (unless I'm missing something
> fundamental) given the framework that Richard Smith laid down for
> constexpr in clang.
>
> So I went ahead and prototyped a quick implementation in clang:
> https://github.com/faisalv/clang/tree/constexpr-lambdas-ref-closures.
>
> Of course, there is a significant compile-time penalty (but this could
> also be optimized further) - but no run time cost.
>
> It makes the following (those of  you who program using dynamic
> languages might be quite familiar with the pattern) well-defined  -
> BUT only at compile time, at run-time, things remain horribly
> undefined :
>
> constexpr auto make_obj(int data) {
>   auto addL = [&] { return ++data; };
>   auto subL = [&] { return --data; };
>   struct {
>     decltype(addL) add;
>     decltype(subL) sub;
>   } ret = {addL, subL};
>  return ret;
> }
>
> constexpr auto Obj1 = make_obj(10);
> static_assert(Obj1.add() == 11, "");
> static_assert(Obj1.add() == 12, "");
> static_assert(Ob1.sub() == 11, "");
>
> auto RuntimeObj2 = Obj1.add(); // This will reliably cause your
> program to crash (but only if executed ;)
>
> You can see further examples here:
> https://github.com/faisalv/clang/blob/constexpr-lambdas-ref-closures/test/CXX/clambdas/saved-frames.cpp
>
> Does anyone see any merit in proposing something like this?


Quite the opposite: I'd be strongly opposed to such a thing.

 Daveed

>  My
> initial thought is that it introduces an asymmetry between compile
> time and run time computation that by itself makes this quite
> unattractive.  I suspect there might be other issues too - such as
> breaking compiler optimizations that might rely on the execution of a
> constexpr function to maintain a certain invariance (are there any
> such optimizations that occur during translation?)
>
> Thoughts?
>
> Thanks!
> Faisal Vali
>
> P.S. I'm sending this out (coincidentally) on April 1st - since the
> idea might seem appropriate for the date  - but the question is an
> earnest one ;)
>
>
>
>
>
> On Thu, Mar 26, 2015 at 3:16 PM, Louis Dionne <ldionne.2@gmail.com> wrote:
>> This is incredibly awesome. I've been waiting for this for so long.
>> I will play with it at soon as I get the time and let me know my thoughts.
>> I think I can provide several use cases for this feature, some of which
>> could definitely motivate a paper.
>>
>> I'm also willing to help write a standard paper, but I must wait for the
>> summer when I have more time on my hands.
>>
>> Thank you Faisal,
>> Louis
>>
>>
>> On Thursday, 26 March 2015 16:01:24 UTC-4, faisalv wrote:
>>>
>>> Hi All,
>>>    Since some of you had expressed interest in constexpr lambdas
>>> (either privately to me or on the list or at Urbana) - and since a
>>> couple of our constexpr godfathers (Gabriel Dos Reis & Richard Smith)
>>> seemed encouragingly un-averse to the general idea when i pinged them
>>> months ago - I went ahead and implemented a quick prototype
>>> (https://github.com/faisalv/clang/tree/constexpr-lambdas (*)) of what
>>> constexpr lambdas might look like in C++, hoping to inform and
>>> facilitate future EWG discussion.
>>>
>>> The easiest way to think about constexpr lamdbas might be to ask
>>> yourself if the equivalent non-lambda code using a literal class with
>>> a constexpr member call-operator would be constexpr. Captures to
>>> references can't escape their scope (at least in this branch ;).
>>> Captures by value obviously can.
>>>
>>> Note: Per my interpretation of preliminary thoughts from Gabby and
>>> Richard, I made the constexpr annotation optional - that is
>>> constexpr-ness of a lambda's call operator is inferred: if the call
>>> operator could be constexpr it is assumed to be so annotated. If you
>>> prefer to explicitly annotate it, you can.  (see comments below as to
>>> where you would add the annotations)
>>>
>>> Consider this highly contrived (braindead) fragment of code below to
>>> get a sense of what's possible with the patch:
>>>
>>> constexpr auto getFactorializer = [] {
>>>  unsigned int optimization[6] = {};
>>>
>>>  auto for_each = [](auto *b, auto *e, auto pred) {
>>>    auto *it = b;
>>>    while (it != e) pred(it++ - b);
>>>  };
>>>
>>>  for_each(optimization, optimization + 6, [&](int n) {
>>>    if (!n) optimization[n] = 1;
>>>    else
>>>      optimization[n] = n * optimization[n-1];
>>>  });
>>>
>>>  auto FacImpl = [=](auto fac, unsigned n) {
>>>    if (n <= 5) return optimization[n];
>>>    return n * fac(fac, n - 1);
>>>  };
>>>  auto Fact = [=](int n) {
>>>    return FacImpl(FacImpl, n);
>>>  };
>>>  return Fact;
>>> };
>>>
>>> constexpr auto Factorial = getFactorializer();
>>>
>>> static_assert(Factorial(5) == 120, "");
>>> static_assert(Factorial(10) == 3628800, "");
>>>
>>>
>>> To see further examples of test-case code that seems to work:
>>>
>>> https://github.com/faisalv/clang/blob/constexpr-lambdas/test/CXX/clambdas/cxx1z-constexpr-lambdas.cpp
>>>
>>> Some technicalities:
>>>  - the conversion operator to fptr for a non-capturing lambda is
>>> always constexpr
>>>  - the closure type behaves as a literal type as long as all of its
>>> capture 'data members' are literals (this can include other closure
>>> objects)
>>>  - the evaluation of a lambda expression is a
>>> core-constant-expression if all the initializations of the captures
>>> are core-constant-expressions
>>>  - the constexprness of the call operator is deduced if not
>>> explicitly specified
>>>
>>> I would certainly appreciate any useful feedback - especially if
>>> anyone has the time to download the patch and play with it and report
>>> any bugs (perceived or real) to me.
>>>
>>> And unless there is overwhelming well reasoned majority opposition to
>>> this idea, I hope to help write a paper on this (I might reach out to
>>> some of you for help - or if you're motivated please reach out to me),
>>> and perhaps we can submit something for the lenexa mailing?
>>>
>>> Thanks!
>>> Faisal Vali
>>>
>>> (*)The llvm revision to use is contained within the Readme file.
>>
>> --
>>
>> ---
>> You received this message because you are subscribed to the Google Groups
>> "ISO C++ Standard - Future Proposals" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to std-proposals+unsubscribe@isocpp.org.
>> To post to this group, send email to std-proposals@isocpp.org.
>> Visit this group at
>> http://groups.google.com/a/isocpp.org/group/std-proposals/.
>

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

.


Author: Faisal Vali <faisalv@gmail.com>
Date: Wed, 1 Apr 2015 08:52:52 -0500
Raw View
On Wed, Apr 1, 2015 at 8:11 AM, David Vandevoorde <daveed@edg.com> wrote:
>
>> On Apr 1, 2015, at 8:01 AM, Faisal Vali <faisalv@gmail.com> wrote:
>>
>> While I was fixing a bug in the constexpr-lambda branch - it occurred
>> to me that true compile time closures -- i.e.constexpr lambdas that
>> capture variables by reference, capture their relevant data-frames on
>> the call stack, but only if executed at compile time) --  are
>> relatively straightforward to implement (unless I'm missing something
>> fundamental) given the framework that Richard Smith laid down for
>> constexpr in clang.
>>
>> So I went ahead and prototyped a quick implementation in clang:
>> https://github.com/faisalv/clang/tree/constexpr-lambdas-ref-closures.
>>
>> Of course, there is a significant compile-time penalty (but this could
>> also be optimized further) - but no run time cost.
>>
>> It makes the following (those of  you who program using dynamic
>> languages might be quite familiar with the pattern) well-defined  -
>> BUT only at compile time, at run-time, things remain horribly
>> undefined :
>>
>> constexpr auto make_obj(int data) {
>>   auto addL = [&] { return ++data; };
>>   auto subL = [&] { return --data; };
>>   struct {
>>     decltype(addL) add;
>>     decltype(subL) sub;
>>   } ret = {addL, subL};
>>  return ret;
>> }
>>
>> constexpr auto Obj1 = make_obj(10);
>> static_assert(Obj1.add() == 11, "");
>> static_assert(Obj1.add() == 12, "");
>> static_assert(Ob1.sub() == 11, "");
>>
>> auto RuntimeObj2 = Obj1.add(); // This will reliably cause your
>> program to crash (but only if executed ;)
>>
>> You can see further examples here:
>> https://github.com/faisalv/clang/blob/constexpr-lambdas-ref-closures/test/CXX/clambdas/saved-frames.cpp
>>
>> Does anyone see any merit in proposing something like this?
>
>
> Quite the opposite: I'd be strongly opposed to such a thing.
>
>         Daveed
>

Is it because compile-time co-routines are not being packaged with them? ;)


>>  My
>> initial thought is that it introduces an asymmetry between compile
>> time and run time computation that by itself makes this quite
>> unattractive.  I suspect there might be other issues too - such as
>> breaking compiler optimizations that might rely on the execution of a
>> constexpr function to maintain a certain invariance (are there any
>> such optimizations that occur during translation?)
>>
>> Thoughts?
>>
>> Thanks!
>> Faisal Vali
>>
>> P.S. I'm sending this out (coincidentally) on April 1st - since the
>> idea might seem appropriate for the date  - but the question is an
>> earnest one ;)
>>
>>
>>
>>
>>
>> On Thu, Mar 26, 2015 at 3:16 PM, Louis Dionne <ldionne.2@gmail.com> wrote:
>>> This is incredibly awesome. I've been waiting for this for so long.
>>> I will play with it at soon as I get the time and let me know my thoughts.
>>> I think I can provide several use cases for this feature, some of which
>>> could definitely motivate a paper.
>>>
>>> I'm also willing to help write a standard paper, but I must wait for the
>>> summer when I have more time on my hands.
>>>
>>> Thank you Faisal,
>>> Louis
>>>
>>>
>>> On Thursday, 26 March 2015 16:01:24 UTC-4, faisalv wrote:
>>>>
>>>> Hi All,
>>>>    Since some of you had expressed interest in constexpr lambdas
>>>> (either privately to me or on the list or at Urbana) - and since a
>>>> couple of our constexpr godfathers (Gabriel Dos Reis & Richard Smith)
>>>> seemed encouragingly un-averse to the general idea when i pinged them
>>>> months ago - I went ahead and implemented a quick prototype
>>>> (https://github.com/faisalv/clang/tree/constexpr-lambdas (*)) of what
>>>> constexpr lambdas might look like in C++, hoping to inform and
>>>> facilitate future EWG discussion.
>>>>
>>>> The easiest way to think about constexpr lamdbas might be to ask
>>>> yourself if the equivalent non-lambda code using a literal class with
>>>> a constexpr member call-operator would be constexpr. Captures to
>>>> references can't escape their scope (at least in this branch ;).
>>>> Captures by value obviously can.
>>>>
>>>> Note: Per my interpretation of preliminary thoughts from Gabby and
>>>> Richard, I made the constexpr annotation optional - that is
>>>> constexpr-ness of a lambda's call operator is inferred: if the call
>>>> operator could be constexpr it is assumed to be so annotated. If you
>>>> prefer to explicitly annotate it, you can.  (see comments below as to
>>>> where you would add the annotations)
>>>>
>>>> Consider this highly contrived (braindead) fragment of code below to
>>>> get a sense of what's possible with the patch:
>>>>
>>>> constexpr auto getFactorializer = [] {
>>>>  unsigned int optimization[6] = {};
>>>>
>>>>  auto for_each = [](auto *b, auto *e, auto pred) {
>>>>    auto *it = b;
>>>>    while (it != e) pred(it++ - b);
>>>>  };
>>>>
>>>>  for_each(optimization, optimization + 6, [&](int n) {
>>>>    if (!n) optimization[n] = 1;
>>>>    else
>>>>      optimization[n] = n * optimization[n-1];
>>>>  });
>>>>
>>>>  auto FacImpl = [=](auto fac, unsigned n) {
>>>>    if (n <= 5) return optimization[n];
>>>>    return n * fac(fac, n - 1);
>>>>  };
>>>>  auto Fact = [=](int n) {
>>>>    return FacImpl(FacImpl, n);
>>>>  };
>>>>  return Fact;
>>>> };
>>>>
>>>> constexpr auto Factorial = getFactorializer();
>>>>
>>>> static_assert(Factorial(5) == 120, "");
>>>> static_assert(Factorial(10) == 3628800, "");
>>>>
>>>>
>>>> To see further examples of test-case code that seems to work:
>>>>
>>>> https://github.com/faisalv/clang/blob/constexpr-lambdas/test/CXX/clambdas/cxx1z-constexpr-lambdas.cpp
>>>>
>>>> Some technicalities:
>>>>  - the conversion operator to fptr for a non-capturing lambda is
>>>> always constexpr
>>>>  - the closure type behaves as a literal type as long as all of its
>>>> capture 'data members' are literals (this can include other closure
>>>> objects)
>>>>  - the evaluation of a lambda expression is a
>>>> core-constant-expression if all the initializations of the captures
>>>> are core-constant-expressions
>>>>  - the constexprness of the call operator is deduced if not
>>>> explicitly specified
>>>>
>>>> I would certainly appreciate any useful feedback - especially if
>>>> anyone has the time to download the patch and play with it and report
>>>> any bugs (perceived or real) to me.
>>>>
>>>> And unless there is overwhelming well reasoned majority opposition to
>>>> this idea, I hope to help write a paper on this (I might reach out to
>>>> some of you for help - or if you're motivated please reach out to me),
>>>> and perhaps we can submit something for the lenexa mailing?
>>>>
>>>> Thanks!
>>>> Faisal Vali
>>>>
>>>> (*)The llvm revision to use is contained within the Readme file.
>>>
>>> --
>>>
>>> ---
>>> You received this message because you are subscribed to the Google Groups
>>> "ISO C++ Standard - Future Proposals" group.
>>> To unsubscribe from this group and stop receiving emails from it, send an
>>> email to std-proposals+unsubscribe@isocpp.org.
>>> To post to this group, send email to std-proposals@isocpp.org.
>>> Visit this group at
>>> http://groups.google.com/a/isocpp.org/group/std-proposals/.
>>
>
> --
>
> ---
> You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

.