Timeline for Why do heavily object-oriented languages avoid having functions as a primitive type?
Current License: CC BY-SA 4.0
13 events
when toggle format | what | by | license | comment | |
---|---|---|---|---|---|
Oct 5, 2022 at 17:29 | comment | added | supercat |
@MSalters: Many aspects of C++ could have been clearer if all types declared as struct had to be standard layout types, while compilers would be free to do anything they wanted with the layout of types declared as class . That would have made it possible to use RTTI on types without virtual members, provided they were declared as class .
|
|
Oct 3, 2022 at 19:57 | comment | added | Peter Cordes | There are other definitions like “OOP means modelling the software after real world concepts” that do not rely on dynamic dispatch. - Thanks, yes, this was the meaning of OOP I was familiar with. A definition of OOP that requires every object to have dynamic dispatch would indeed require virtual member-functions. | |
Oct 3, 2022 at 13:00 | comment | added | MSalters |
@PeterCordes: The decision that C++ classes are not "objects in the OO sense" if they don't have virtual functions is pretty intentional. RTTI in C++ only works for classes that have at least one virtual function. C++ has objective distinctions between primitive types, OO class types and non-OO class types. <typetraits> even tells you what's what.
|
|
Oct 3, 2022 at 12:01 | comment | added | amon | And yes, I agree that C/C++ function pointers are primitive types. So for the specific case of C++, OP's question could be answered “C++ is multi-paradigm, function pointers are available”. But Java and C# used a different design where wrapper objects allow the overall language to be simpler, and even C++ frequently uses such wrapper objects (e.g. for lambdas or bound methods, requiring type erasure per std::function). | |
Oct 3, 2022 at 11:59 | comment | added | amon | @PeterCordes Under any mainstream mechanical OOP definition I know (e.g. Kay's method passing / extreme late binding; Encapsulation–Inheritance–Polymorphism; OOP is when dynamic dispatch), virtual methods or equivalent runtime polymorphism are indeed the defining feature of OOP. In static type systems, this also implies that we only get OOP if we interact with an object through an interface/base class. This means that a C++ class/struct alone does not provide OOP. There are other definitions like “OOP means modelling the software after real world concepts” that do not rely on dynamic dispatch. | |
Oct 3, 2022 at 10:31 | comment | added | Peter Cordes | Function pointers are different from data pointers, yes, but having "functions as a primitive type" doesn't imply that they should be mutable. In fact having them as a separate thing from data references or integers makes them even more of a first-class citizen on par with those things, not a special case of another primitive type. As you say, C++ is designed to be ahead-of-time compiled, only executing machine-code that was generated before the program started running. Possibly from ROM. So it's compatible with pure Harvard machines. | |
Oct 3, 2022 at 10:24 | comment | added | Peter Cordes | You're arguing that a C++ class isn't object in the OOP sense if it doesn't have virtual member functions? I'm not an expert on OOP theory, but you don't always need polymorphism for every type to be doing OOP, do you? So you can have objects, especially helper or sub-objects but not limited to that, where the static type uniquely determines the member function being called, not dispatch table needed. That's a special case of OOP where polymorphism isn't needed. Partly this is a nitpick; your overall point does work that this is C++'s traditional way to do OOP style polymorphism. | |
Oct 3, 2022 at 10:00 | comment | added | amon | (So there is another answer to be written about how function pointers are not ordinary pointers, if we consider the existence of Harvard architecture computers. A portable language like C++ or Java MUST treat data and code as distinct categories, but can use the aforementioned techniques like function objects to smooth over that difference. OP correctly points out the existence of Lisps as an example where data and code are interchangeable, but that is an abstraction.) | |
Oct 3, 2022 at 9:56 | comment | added | amon |
@PeterCordes This answer uses the words “object” and “class” in the OOP sense, not in the C/C++ sense that also uses these terms for value types. A function pointer by itself does not carry RTTI and is then not an object (and even in the standard C++ viewpoint, function pointers are not ordinary pointers). Similarly, C# delegates are not ordinary objects. I've included C++ here because it is useful for contrasting with Java/C#. For example, std::function is a library-level implementation of the language-level type erasure Java does with its functional interfaces.
|
|
Oct 3, 2022 at 6:38 | comment | added | Peter Cordes |
Anyway, C++ is not limited to Java's way of doing things, so it's weird to lump it in with them. You can pass around raw function pointers. Or if you want to do your polymorphism differently, you can roll your own, or for example use std::visit on std::variant objects by value, instead of needing references for polymorphism.
|
|
Oct 3, 2022 at 6:32 | comment | added | Peter Cordes |
Also, C++ has had "free" functions since the outset, inherited from C, and static member functions. You can take the address of a static or non-member function. But that's not OOP at all. It also has syntax for pointer-to-member-function (which require a this object to call it on); using std::invoke makes it easy to use those pointers on any object, mixing and member-function pointers and object pointers (of compatible types). isocpp.org/wiki/faq/pointers-to-members . But that was possible before C++11 (C++11 std::mem_fn and std::bind from <functional> make it easier.)
|
|
Oct 3, 2022 at 6:01 | comment | added | Peter Cordes |
Your struct Class {Method methods[]; }; is the vtable, right? In C++ implementations, that only exists in classes that have any virtual member functions. "Standard layout" classes are guaranteed not to have any extra shenanigans like that, so the struct/class address is also the address of the first member. See also How do objects work in x86 at the assembly level? / In C++, is it valid to treat scalar members of a struct as if they comprised an array? and
|
|
Oct 2, 2022 at 21:53 | history | answered | amon | CC BY-SA 4.0 |