Skip to content

UFCS: function call starts UFCS chaining #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

filipsajdak
Copy link
Contributor

@filipsajdak filipsajdak commented Sep 26, 2022

On the stdio example there is a call to c-function:

myfile := fopen("xyzzy", "w");
myfile.fprintf( "Hello with UFCS!" );
myfile.fclose();

This is great but we can do better than that. What I don't like about this approach is the lost opportunity to save us from resource leak. What I would like to do is to have a possibility to wrap the return FILE* into something that will clean things up.

I have implemented the feature that starts UFCS chaining on the function call of syntax func1().func2() (it can go recursively further). That brings us more interesting features like wrapping things into smart pointers in one call.

#include <vector>
#include <memory>

template <typename T, typename R>
auto on_scope_exit(T* f, R(*close)(T*)) {
    return std::unique_ptr<T, decltype(close)>{f, close};
}

main: () -> int = {
    f2 := fopen("variable2.txt", "w").on_scope_exit(fclose);
    f2.get().fprintf("you can handle smart_ptrs without changing behaviour of UFCS");

    m := fopen("manual.txt", "w");
    m.fprintf("Manual handling still works");
    m.fclose();
}

That can go even further. Thanks to #13 the code can be even simpler:

    f2 := fopen("variable2.txt", "w").on_scope_exit(fclose);
    f2.fprintf("you can handle smart_ptrs without changing behaviour of UFCS");

    m := fopen("manual.txt", "w");
    m.fprintf("Manual handling still works");
    m.fclose();

    f := fopen("variable.txt", "w").on_scope_exit(fclose);
    f.fprintf("This one use variable and\n");
    f.fprintf("    separate\n");
    f.fprintf("        calls\n");
    f.fprintf("            of fprintfs");

    fopen("one_liner.txt", "w").on_scope_exit(fclose)
                               .fprintf("This is oneliner!!\n\nAnd it just close automatically");
}

The last use case (one-liner) makes me think that UFCS brings some risk of leaking resources when chained. When results of fopen will be used by fprintf directly the pointer to file will be lost.

    // bad use
    fopen("one_liner.txt", "w").fprintf("there is a leak on the end of this function");

I will investigate if there is a possibility to block potentially leaking combinations. Smart pointers are safe and we can eliminate cases when rvalue pointers are passed to a chained function.

@filipsajdak filipsajdak force-pushed the fsajdak-function-call-starts-ufcs-chaining branch from 105feda to bb68fd9 Compare September 26, 2022 01:10
@JohelEGP
Copy link
Contributor

    // bad use
    fopen("one_liner.txt", "w").fprintf("there is a leak on the end of this function");

I will investigate if there is a possibility to block potentially leaking combinations.

https://github.com/isocpp/CppCoreGuidelines/blob/master/docs/Lifetime.pdf should take care of that. It mentions:

Additionally, for convenient adoption without modifying existing standard library headers, the following well-known standard types are treated as-if annotated as Owners: stack, queue, priority_queue, optional, variant, any, and regex.

It could do similarly for fopen. If it were my_fopen instead, I think you're out of luck if you don't wrap it safely.

@filipsajdak
Copy link
Contributor Author

Another interesting extension can be proposed to make calling functions like fprintf that are not returning FILE* and stops the chaining.

visit: (in v:_, in callable:_) -> auto = {
    return callable(v);
}

main: () -> int = {
    fopen("one_liner.txt", "w").on_scope_exit(fclose).get().visit(:(e:_) = {
        e.fprintf("1) This is oneliner!!\n\n");
        e.fprintf("2) This is oneliner!!\n\n");
        e.fprintf("3) This is oneliner!!\n\n");
        e.fprintf("4) This is oneliner!!\n\n");
        e.fprintf("5) This is oneliner!!\n\n");
        e.fprintf("6) This is oneliner!!\n\n");
    });
}

@hsutter
Copy link
Owner

hsutter commented Oct 1, 2022

(Repeating from #17)
Interim ack: Thanks! Yes, I've been meaning to add chaining. I was thinking of implementing it later in the same function and remove this special case part of the function (I dislike that there are two paths that deal with . operator differently)... let me keep this PR open without action until I get a chance to look at it again later.

@hsutter hsutter self-assigned this Oct 1, 2022
@filipsajdak filipsajdak force-pushed the fsajdak-function-call-starts-ufcs-chaining branch from be9ff82 to 7823650 Compare October 2, 2022 01:52
@filipsajdak filipsajdak force-pushed the fsajdak-function-call-starts-ufcs-chaining branch from 7823650 to a3ffe9b Compare October 6, 2022 08:41
@filipsajdak filipsajdak force-pushed the fsajdak-function-call-starts-ufcs-chaining branch 2 times, most recently from cea865b to 62a9472 Compare October 11, 2022 05:12
@filipsajdak filipsajdak force-pushed the fsajdak-function-call-starts-ufcs-chaining branch from 62a9472 to 37eb661 Compare October 18, 2022 17:21
@filipsajdak filipsajdak force-pushed the fsajdak-function-call-starts-ufcs-chaining branch from 37eb661 to 9b556e4 Compare October 20, 2022 23:12
@filipsajdak filipsajdak force-pushed the fsajdak-function-call-starts-ufcs-chaining branch from 9b556e4 to 9f12c53 Compare October 30, 2022 20:01
@filipsajdak filipsajdak force-pushed the fsajdak-function-call-starts-ufcs-chaining branch 2 times, most recently from f263cba to 0ff43ba Compare December 6, 2022 22:16
@filipsajdak filipsajdak force-pushed the fsajdak-function-call-starts-ufcs-chaining branch from 0ff43ba to ef5f875 Compare December 15, 2022 23:01
@hsutter
Copy link
Owner

hsutter commented Dec 16, 2022

Picking this up: I'm willing to consider UFCS chaining, even as an additional section within the function. Before I look at this more closely... do you want to pursue this now? if yes does it need to be rebased including to mirror the updates I just made to the current UFCS code (we want to stay consistent)? Thanks!

@hsutter hsutter mentioned this pull request Dec 16, 2022
@hsutter
Copy link
Owner

hsutter commented Dec 16, 2022

Adding bidirectional xrefs: How does this relate to #17?

@filipsajdak
Copy link
Contributor Author

This is for a case when there is a free function call and the chaining starts on the function result.

#17 is for the cases when the first call is done on the object by calling its method.

@filipsajdak
Copy link
Contributor Author

I am pretty sure it needs to be rebased. I can do that tomorrow.

@filipsajdak
Copy link
Contributor Author

This PR is replaced by: #169

@filipsajdak filipsajdak deleted the fsajdak-function-call-starts-ufcs-chaining branch December 22, 2022 10:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants