This is an archive of the discontinued LLVM Phabricator instance.

[libc++] Eliminate the `__function_like` helper.
ClosedPublic

Authored by Quuxplusone on Jan 3 2022, 6:05 PM.

Details

Reviewers
ldionne
var-const
Group Reviewers
Restricted Project
Commits
rG63a991d03589: [libc++] Eliminate the `__function_like` helper.
Summary

As prefigured in the comments on D115315.

This gives us one unified style for all niebloids, and also simplifies the modulemap: it's important that we do this simplification before the modulemap gets completely out of hand.

(This was split out of D116384. @ldionne, this is the PR where we can argue about whether __function_like provides a benefit to justify its IMO-high maintenance cost.)

Diff Detail

Event Timeline

Quuxplusone created this revision.Jan 3 2022, 6:05 PM
Quuxplusone requested review of this revision.Jan 3 2022, 6:05 PM
Herald added 1 blocking reviewer(s): Restricted Project. · View Herald TranscriptJan 3 2022, 6:05 PM

The maintenance cost you're referring to is the modulemap gymnastics, right? If so, we could eliminate that by using a macro.

ldionne requested changes to this revision.Jan 4 2022, 9:37 AM

Arthur and I just spoke offline, and I explained my opinion about what I think are the possible outcomes:

  1. The specification keeps making a bunch of stuff IFNDR about Niebloids, and so we keep the protections we currently have (basically we keep __function_like under one form or another). This prevents users from starting to depend on implementation details, and that's important.
  1. The specification says what all implementations are actually doing, i.e. implement Niebloids the same way CPOs are specified (as function objects). Then, we could actually provide those guarantees to users in a portable way, which would be even better IMO. We could guarantee that those function objects are copyable, etc. That would make it possible to use them with higher order functions and a bunch of other interesting things that users can't do portably right now, but will clearly all fall in the trap of using.

I don't have a super strong preference for (1) or (2), but I think (2) provides more usefulness to users in a portable way without really removing any freedom from implementers -- concretely, I doubt we're ever going to implement Niebloids differently than using a function object. Arthur is going to file a LWG issue to discuss the possibility of specifying Niebloids more strictly in the standard so as to resolve the implementation divergence we currently have.

Requesting changes until we have a LWG discussion going.

This revision now requires changes to proceed.Jan 4 2022, 9:37 AM

(quoting comments from the previous discussion in the other patch)

Whichever one we choose, the user might (accidentally or on purpose) end up relying on it. They'll have some template that does one thing if the type is copyable and a different thing if it's not, and then boom, technically we can't change that without an ABI break.

True, but since we have to choose, it seems like forbidding operations that aren't explicitly supported prevents more common cases of misuse than allowing them. Somebody accidentally copying a function object seems more likely to happen than a template switching on copyability.

we actually can change this stuff without worrying about the breakage to users.

I think there are two different considerations here: whether the Standard allows us to change these things (yes) and whether these changes would provide good user experience (that is, avoid breaking anybody or at least break as few people as possible).

FWIW, today, GCC accepts and MSVC rejects https://godbolt.org/z/hhae7zEf9

MSVC derives the function objects from a helper class _Not_quite_object which is similar to __function_like in intention. GCC doesn't do anything like that, AFAICS.

Rebased on main. Added a test for the properties we intend to support, in the style of "cpo.compile.pass.cpp".
(Maybe it should go in libcxx/test/libcxx/, but initially I wanted to keep it directly adjacent to "cpo.compile.pass.cpp". I can move it if we like.)

ldionne accepted this revision.Jan 20 2022, 10:18 AM

Just to give an update on what happened with the LWG thread Arthur created, basically LWG said "write a paper for LEWG". I think it makes sense to ask that, since that is indeed a design change.

Therefore, what I am suggesting we do here is make this change and write a paper saying basically that libc++ and libstdc++ already do it, and MSVC is trying to reduce the API surface (like libc++ prior to this change). However, given that the proposed behavior is both simpler for all implementations AND also more useful for users (since they can use these niebloids in higher order functions and so on), AND it would resolve implementation divergence, it seems like really a good change to make, so I'd be surprised to see LEWG reject it.

In other words, I'm fine with this change not because it makes us less strict (I dislike that part), but because I'm confident that it's going to be what the Standard mandates once we've made this change and can point at libc++ and libstdc++ as having made that decision already.

libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp
16 ↗(On Diff #400297)

Missing #include <type_traits>.

This revision is now accepted and ready to land.Jan 20 2022, 10:18 AM
libcxx/include/module.modulemap