Timeline for The "blub paradox" and c++
Current License: CC BY-SA 3.0
13 events
| when toggle format | what | by | license | comment | |
|---|---|---|---|---|---|
| Apr 29, 2019 at 15:06 | comment | added | Caleth | Let us continue this discussion in chat. | |
| Apr 29, 2019 at 15:04 | comment | added | cmaster - reinstate monica | @Caleth While it's possible in Objective-C to pass object(s) and selector(s) at different times, the usual usecase was to pass them together. A button's action, for instance, could be set with a single call that passed both object and selector. The only exception to this that I am aware of was the generic array type that included a member function that took only a selector and invoked it on all the objects stored in the array - an operation that was used rather sparingly, and is rather questionable IMHO. That's why I think that the bundled object and member approach is a better C++ equivalent. | |
| Apr 29, 2019 at 14:40 | comment | added | Caleth | @cmaster I was assuming the object(s) and the member(s) to call were passed to the library at different times | |
| Apr 29, 2019 at 14:39 | comment | added | cmaster - reinstate monica | @Caleth Ah, ok, so basically the type-deleted closure idea. Nevertheless, why not just include the object pointer in the closure? Like template<class ClassT> std::function<Ret()> make_erased(ClassT* o, Ret(ClassT::*member)()) { return [o, member](){ return (o->*member)(); }; } This should work perfectly in C++, and is probably the most fitting solution in most cases. Frankly, I didn't grasp the intended use of std::function<> when I wrote this answer 3 years ago, it's what makes this kind of parameter passing possible. Nevertheless, Objective-C doesn't require such complex incantations... | |
| Apr 29, 2019 at 14:08 | comment | added | Caleth | @cmaster among others void *, and std::function<Ret(void*)>, aided by a wrapper like template<class ClassT> std::function<Ret(void*)> make_erased(Ret(ClassT::*member)()) { return [member](void * ptr){ return (static_cast<ClassT>(ptr).*member)(); }; }. You still need to co-ordinate that object of the correct type are used, so it's often easier to expose it as a template | |
| Apr 29, 2019 at 13:59 | comment | added | cmaster - reinstate monica | @Caleth Now you got me curious: You mean, it's possible to pass both an object pointer and a pointer to one of its members to a dynamically linked library function, and have that library function call the object's member function correctly without knowing the object's type? I would have thought that you need to encapsulate both object and member function pointer into a closure that is passed via std::function<> to achieve type deletion. More precisely: What argument types would the library function need to accept to allow passing an arbitrary member function of an arbitrary object? | |
| Apr 29, 2019 at 9:02 | comment | added | Caleth | @cmaster C++ let's you construct a std::function<Ret(ClassT)> from &ClassT::Member, i.e. the name of a member function, similarly Java's ClassT::Member, similarly C#'s o -> o.Member() | |
| May 20, 2016 at 6:11 | comment | added | cmaster - reinstate monica | @Jules Your arguments are precisely what the Blub-Paradox is about: As a proficient C++ programmer, you don't see these as limitations. However, they are limitations, and other languages like C99 are more powerful in these specific points. To your last point: There are workarounds possible in many languages, but I don't know one that really allows you to pass the name of any method to some other class and have it call it on some object that you provide as well. | |
| May 19, 2016 at 17:02 | comment | added | Jules | "I have not seen a similarly flexible way to define a callback in any other language yet (though I'd be very interested to hear about them!). " -- in Java, you can write object::method and it will be converted into an instance of whatever interface the receiving code expects. C# has delegates. Every object-functional language has this feature because it's basically the point of cross-section of the two paradigms. | |
| May 19, 2016 at 16:58 | comment | added | Jules | "In C++ you cannot write down the type of a lambda. You can't even typedef it. Thus, there is no way to pass around a lambda, or store a reference to it in an object" -- that's what std::function is for. | |
| May 19, 2016 at 16:57 | comment | added | Jules | "In C++ you cannot write down the type of a VLA" [...] -- in C++, C99-style VLAs are unnecessary, because we have std::vector. While it's a little less efficient due to not using stack allocation, it is functionally isomorphic to a VLA, so doesn't really count as a "blub" type issue: C++ programmers can look at how it works and just say, "ah yes, C does that more efficiently than C++". | |
| May 18, 2016 at 21:10 | comment | added | Mason Wheeler | I have not seen a similarly flexible way to define a callback in any other language yet (though I'd be very interested to hear about them!) What you just describes sounds exactly like the way event-driven UI code works in Delphi. (And in .NET WinForms, which was heavily influenced by Delphi.) | |
| May 18, 2016 at 21:03 | history | answered | cmaster - reinstate monica | CC BY-SA 3.0 |