C++ Logo

std-proposals

Advanced search

Re: [std-proposals] A drift for c++ decorators;

From: Jeremy Rifkin <jeremy_at_[hidden]>
Date: Sun, 27 Oct 2024 16:37:32 -0500
Hi,

> If the code is replaced during the pre-compilation period

What pre-compilation period do you refer to? This couldn't be done
during the preprocessor as it relies on knowledge of function
declarations and definitions.

Would these decorations be applied to function declarations or
definitions? Would they require the full definition of the decorator?

You seem to be proposing these decorators make call-site modifications
but to me this seems like the less ideal way to approach this. If this
ever were to be a thing I would expect an internal transformation along
the following lines:

template <class Func, class... Args>
auto print_logs(Func&& func, Args&& ...args) {
    printf("this is a log\n");
    return func(std::forward<Args>(args)...);
}
@print_logs
int add(int a, int b) {
    return a + b;
}

=>

template <class Func, class... Args>
auto print_logs(Func&& func, Args&& ...args) {
    printf("this is a log\n");
    return func(std::forward<Args>(args)...);
}

int add_impl(int a, int b) {
    return a + b;
}

int add(int a, int b) {
    return print_logs(add_impl, std::forward<int>(a), std::forward<int>(b));
}

This would allow such decorators to be omitted at the point of function
declaration and included just at the point of function definition. That
would be nice in a lot of ways but it would also introduce some ODR complexities.



Cheers,
Jeremy


On Oct 27 2024, at 8:59 am, zys via Std-Proposals
<std-proposals_at_[hidden]> wrote:

> Dear arthur:
>
> I just want to implement a syntactic sugar for "function hook" and
> make it support member functions. Unfortunately, I did not find
> relevant content in N3617 and P0834.
> If the code is replaced during the pre-compilation period, it will not
> involve issues related to class inheritance. The override calls order
> should follow existing C++ rules, so there won't be any override
> problems. Of course, the developer needs to fix compiler's warnings.
> I modified the previous example to better illustrate what I want to achieve.
>
> @print_logs(file_name, file_line) // Execute print_logs before
> executing add.
> int add(int a, int b)
> {
> return a + b;
> }
> int common()
> {
> const char* file_name = __FILE__;
> const int file_line = __LINE__;
> add(1, 2); // print: "[proposal.cpp:21]this is a log\n"
> // Replace the <add> above with the following code at pre-compilation.
> /*
> ([&]{ return print_logs(file_name, file_line, [&](){
> return add(1, 2);
> }); }());
> */
> return 0;
> }
>
> struct math
> {
> [[hook print_logs]]
> int add(int a, int b) { return a + b; }
> };
> int instead_of_class()
> {
> const char* file_name = __FILE__;
> const int file_line = __LINE__;
> math m;
> m.add(1, 2); // print: "[proposal.cpp:35]this is a log\n"
> // Replace the <m.add> above with the following code at pre-compilation.
> /*
> ([&] { return print_logs(file_name, file_line, [&](){
> return m.add(1,2);
> }); }());
> */
> return 0;
> }
>
>
> "@print_logs" should change to "[[hook print_logs(file_name,
> file_line)]]", I think.
>
> At 2024-10-27 04:44:50, "Arthur O'Dwyer" <arthur.j.odwyer_at_[hidden]> wrote:
>
>
>> Are you proposing that `m.add(1,2)` should be just syntactic sugar
>> for `print_logs([]m.add, 1, 2)`, where []x.y is N3617's and P0834's
>> (quite nice, but never yet adopted-by-C++) syntactic sugar for
>> `[&](auto&&... args){return m.add(decltype(args)(args)...);}` ? Or is
>> it syntactic sugar for something else? Or is `m.add` itself now
>> really some other kind of entity? or what?
>> If you are proposing exactly the P0834-style approach, then what
>> happens with something like `(++p)->add(1, 2)`?
>> Also, how would this (whatever it is) interact with forward-declarations?...
>> int f(); // foo.h
>> @decorated int f() { return 42; } // foo.cpp
>>
>> Also, your item (1) mentions inheritance, but I don't see evidence
>> that you've thought about what your feature should do in the presence
>> of inheritance, e.g.
>> struct Base { virtual int f(); @decorated virtual int g(); }; //
>> is this OK?
>> struct Derived : Base {
>> @decorated int f() override; // is this OK?
>> int g() override; // what about this?
>> };
>> Derived d;
>> d.g(); // does this call go via the decorator, or not?
>>
>> Meanwhile, you should probably be aware that in the current year
>> (2024) Brian Bi attempted with P3254 to clear the way for treating
>> `_at_xyz` as a single token — but EWG didn't care for that (at least not
>> at the moment, without any further feature work to build on it). My
>> impression, though, is that he was trying to sell @xyz as a possible
>> future replacement for [[xyz]] (i.e. attributes), rather than as a
>> totally new thing (decorators). So this is a point against your
>> syntax, but only a very minor point IMHO.
>> https://github.com/cplusplus/papers/issues/1914
>>
>> –Arthur
>>
>>
>>
>>> On Sat, Oct 26, 2024 at 1:25 PM zys via Std-Proposals
>>> <std-proposals_at_[hidden]> wrote:
>>>
>>>> Dear all:
>>>> When I want to execute additional code before functions without
>>>> changing the source code, there are several approaches I can take:
>>>> Use C++ inheritance and override the original function.
>>>> Use function hooks at the compile time.
>>>> Use lambda functions, etc.
>>>> In Python, decorators can assist developers in achieving this and
>>>> are widely used. Therefore, it is suggested that C++ also adds
>>>> decorators as a syntactic sugar to help developers quickly
>>>> implement the execution of extra code before and after functions.
>>>> for examples:
>>>> #include <stdio.h>
>>>> #include <iostream>
>>>>
>>>> template <class Func, class... Args>
>>>> auto print_logs(Func &&func, Args &&...args)
>>>> {
>>>> printf("this is a log\n");
>>>> return func(std::forward<Args>(args)...);
>>>> }
>>>>
>>>> @print_logs // Execute print_logs before executing add.
>>>> int add(int a, int b)
>>>> {
>>>> return a + b;
>>>> }
>>>> int common()
>>>> {
>>>> add(1, 2); // print "this is a log\n"
>>>> // Replace the add above with the following code at pre-compilation.
>>>> // print_logs(add, 1, 2);
>>>> return 0;
>>>> }
>>>>
>>>> struct math
>>>> {
>>>> @print_logs
>>>> int add(int a, int b) { return a + b; }
>>>> };
>>>> int instead_of_lamda()
>>>> {
>>>> math m;
>>>> m.add(1, 2); // print "this is a log\n"
>>>> // Replace the add above with the following code at pre-compilation.
>>>> // print_logs([&](int a, int b)
>>>> // { return m.add(a, b); }, 1, 2);
>>>> return 0;
>>>> }
>>>> --
>>>> Std-Proposals mailing list
>>>> Std-Proposals_at_[hidden]
>>>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
> --
>
> Std-Proposals mailing list
>
> Std-Proposals_at_[hidden]
>
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Received on 2024-10-27 21:37:36