Hi To all: My question is that what techniques were used for
Inheritance, Encapsulation and polymorphism in C++ before the
invention of OOP. Please explain and if any link share it.
Ignoring the question of what you mean by 'in C++ before OOP', then with the C language you'd be looking at
void pointers - the C language allows you to address memory directly, storing addresses in variables with a pointer type. Most pointers point to a known type (e.g. char * is a pointer to a character) but a special type void * is a pointer to a raw piece of memory. Many libraries hid internal structures in void pointers, sometimes called 'Handles'.
function pointers - as with data pointers, a pointer could hold the address of a function in memory. This allowed for assigning different behaviour by swapping functions in and out of variables.
structs - the primary mechanism for grouping data. Combining structs with function pointers gets a rudimentary form of 'class', albeit without the magic of inheritance or polymorphism. By hiding data behind a void * within a struct you get a basic form of encapsulation.
preprocessor - lots of magic could be made to happen in the preprocessor by turning one type into another type or unpacking things on the fly. Void pointers would often be accessed using preprocessor macros which unpacked them safely.
Inheritance was not generally an aspect of the C programming idiom so you rarely come across it in C programs. Where I've seen something akin to it it's generally accomplished by using some kind of void pointer hackery where the first field of a struct is a void pointer to a parent and initialisation functions are used to copy function pointers into a makeshift v-table. However, it's cumbersome and fragile and the C language was not really designed to support object-orientation natively - you can do it but the pipework is very visible.
Getting back to the 'in C++ before oop' part - it's worth remembering that there was no C++ before oop. OO concepts, and OO languages, have been around for much longer than C++. C++ isn't even a pure OO language - it's a multi-paradigm language which supports OO.
Related
Java is considered an OOP language, despite it not quite being purely OOP. Java contains 8 primitives, and in an interview, James Gosling explains why:
Bill Venners: Why are there primitive types in Java? Why wasn't
everything just an object?
James Gosling: Totally an efficiency thing. There are all kinds of
people who have built systems where ints and that are all objects.
There are a variety of ways to do that, and all of them have some
pretty serious problems. Some of them are just slow, because they
allocate memory for everything. Some of them try to do objects where
sometimes they are objects, sometimes they are not (which is what the
standard LISP system did), and then things get really weird. It kind
of works, but it's strange.
So it seems that both memory and speed are issues that Java's primitives solve. However, this got me wondering how can a language be true, pure object-oriented?
If only a byte primitive existed, you could build from there. Creating integers, chars and eventually floats and doubles. But without any base structure at all, how could you build anything? Isn't at least some base primitive necessary? In other words, isn't a base data-structure needed in to expand from?
If you're asking if there are languages that have no way to interact with primitive types, then you might want to look at something like Scala. From that page:
Scala is a pure object-oriented language in the sense that every value is an object.
However, as you point out (for Kotlin):
the compiler maps them to JVM primitives when at all possible to save memory
If your definition of what object-oriented languages can be requires that everything is always represented as an object, then a purely object-oriented language is impossible. You can't build a language that runs on a real computer that only has objects. This is because the computer must have a way to represent the data natively. This is essentially what primitives in object-oriented languages are: The native forms of data that the underlying computer (or VM) can represent. No matter what you do, you will always need to have some non-object representation of data in order for the computer to do operations with it. Even if you built a JavaScript interpreter that really represented primitives as objects, in order to add two integers, the interpreter would have to have load the integers into CPU registers and use some form of an add instruction.
But that explanation sort of misses the point of object-oriented programming. A programming language is not the same as a program. Languages are just a tool for us to make computers do what we want - they don't actually exist at runtime. You would probably say that a program written in Kotlin or Scala is more object-oriented than a program written in C, despite both languages compiling to the same assembly instructions at runtime.
So, if you relax your definition of pure object-oriented programming to no longer be concerned with what the runtime representation of data is, then you'll find that purely object-oriented languages are possible. When programming Scala, you never interact with anything that's not an object. Even if your Int becomes a 'primitive' at runtime, it doesn't really matter, because you, as the programmer, never really have to think about that (at least, in an ideal world where performance and memory never matter). The language definition of Scala doesn't include the concept of primitives at all - they are part of the implementation of the language, not the language itself.
As far your example of Java goes, Java probably isn't a purely object-oriented language by most definitions. It is, however, mostly object-oriented. Java is often mentioned as the de facto object oriented language because it was much more object oriented than what came before it.
Even further, the term object-oriented doesn't really have a definitive meaning. To some people it might mean that everything has to be an object, and to others it might just mean that there need to be objects, some definitions require the concept of classes, some don't, etc.
Assume we have a drawing program with different elements, such as circle, rectangle, triangle and so on. Different kinds of objects that will all need similar function such as draw() to display themselves.
I wonder how would a programmer approach the problem that is nowadays typically solved by polymorphism, i.e. go through a collection of non-identical elements and invoke common functionality across the different objects.
One way that comes to mind is to have a struct with a function pointer to the appropriate function (or index in a function pointer array) as well as a void pointer to the actual instance, and pass the pointer which is cast to the proper type in the function. But that is just how I - a guy who is clueless on the subject would do it.
I do realize this might be a noobish question, but since I haven't been around in the "olden" days, I really wonder how was this problem tackled. What kind of approach was used in procedural programming and did it have a performance benefit, since we all do know polymorphism has an overhead even in fast languages like C++, due to the virtual method lookup.
A really simple example.
If this interest you you can find more of this in the Linux Kernel.
#include <stdio.h>
struct shape {
void (*say_hello)(void);
};
void circle_say_hello(void)
{
printf("Hi I am circle!\n");
}
void square_say_hello(void)
{
printf("Meh I am square.\n");
}
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
int main(int argc, char *argv[])
{
struct shape circle = { .say_hello = circle_say_hello, };
struct shape square = { .say_hello = square_say_hello, };
struct shape* shapes[] = {&circle, &square};
int i;
for (i = 0; i < ARRAY_SIZE(shapes); i++) {
if (shapes[i] && shapes[i]->say_hello)
shapes[i]->say_hello();
}
return 0;
}
In procedural languages such as C, this would be tackled by defining separate implementations of the draw() function for each custom data type (probably represented as a struct). Any common functionality would be factored out into a separate function which operated on shared elements of each struct (such as the x and y coordinate of the center of the object, which would appear in each one). From a code and functionality perspective, this isn't much different from the OOP layout utilizing polymorphism, where you still have to implement a shared draw() method in a base class and override it in the specific sub-class. In the case of a procedural language, we just wouldn't split these function definitions out into separate "objects".
There are some fancy ways to get object-like behavior out of a procedural language, such as a union type or a single monolithic type with extra booleans to determine if a particular element is in use. That would allow you to write a single draw() function that could perform logic switching based on which elements were enabled. In practice, the only place I have seen much of that is in CORBA-based systems where a program written in C had to mimic some of the behavior of an OOP language which was propagated through the IDL (i.e. translation of Java objects to constructs which could be decoded into C-style structs).
As for the overhead of virtual method lookup in languages such as C++ and Java, that is something that cannot be entirely avoided in an object-oriented language. It can be pretty well mitigated with proper use of the final keyword (which allows the compiler / JVM to optimize the method lookup tables).
This is not a direct answer to your example but an address to your comment, which shows a wrong perspective IMHO
I was just wondering about that particular problem, mostly interested
if there is a more efficient way that avoids the performance overhead
of virtual methods
There is something to understand here. Everything has a tradeoff. Design patterns and OO have all the known advantages we have come to love, but have disadvantages as well e.g. too many classes, memory overhead, performance overhead due to many method calls etc.
On the other hand the old "procedural" way had some advantages also to be objective; it was "simple" to code (no need to think how to design a system, just put everything in main) and had less overhead in many aspects (less memory overhead as less classes are needed and more compact objects -no need for virtual tables etc- and less method calls so perhaps better performance, no performance overhead for dynamic binding - whatever the overhead is nowadays anyway...-).
But it is not what the trade-offs of a particular problem instance are, it is what the experience has shown what is the proper way to build software. Reuse of code that is modular and assists in separate testing (quality assurance), readable, maintainable, flexible to extend are attributes that have been well understood that should be the main driver in software development.
So there are certain cases that a really good programmer in C/C++ could do the "old way" as you say, but is the performance benefit that it incur for this particular program worth the fact that no-one would be able to maintain or sustain it afterwards?
To give another similar example: You could ask in the same fashion?
Why multi-tier architectures in web development? Just put everything into one server and it will be A LOT FASTER since there will be no latency in querying the back-end and all the layers for the data of the UI or the network latency for a query of a remote database etc.
Sure, you have a point. But then ask your self, can this scale as load increases? The answer is no. So is scalability important to you or you want to keep the "put everything in one server" idea? If your income comes from e-sites, the fact that you can not serve more customers would not make your client happy just because you served the first 100 really fast...Anyway this is my opinion
I have some maybe stupid question. What is the difference between C++ and objectice-c. Is there IDE for objective-c for linux ?
I'm going to expand a bit on DaVinci's point 1.
First the similarities:
Objective-C and C++ were both originally based on C. Both languages support an object oriented model. That's where the similarities end.
Objective-C is a strict superset of C, C++ is not. Any C program is also an Objective-C program. This is not necessarily the case with C++.
The syntax of Objective-C's OO extensions is closer to the syntax of Smalltalk than that of C whereas the reverse is the case with C++.
The philosophies behind the OO models is completely different too. Objective-C's model is dynamic in the spirit of Smalltalk. C++'s model is more static. With Objective-C, you send messages to objects and the object decides at run time how it is going to respond to the message. With C++ the methods that an object responds to - even the virtual ones - are defined at compile time. This makes Objective-C's object model immensely more powerful than C++'s object model. For instance, you can add whole sets of new methods to existing classes without using inheritance. You can even replace method implementations on the fly.
This all comes at a cost of course. Sending messages to Objective-C objects is quite a bit slower than calling C++ virtual functions. However, I think the benefits are worth the cost and you can always drop back to C for performance critical sections of code.
NB there is also a language called Objective-C++ which is the Objective-C OO extensions built on top of C++ instead of C.
they are simply two quite different languages.
I think gnustep is the only objective-C environment/library, it also has a IDE: project center, however Objective-Cs home is primarily on Apple products.
Are there any advantages to using object-oriented programming (OOP) in a functional programming (FP) context?
I have been using F# for some time now, and I noticed that the more my functions are stateless, the less I need to have them as methods of objects. In particular, there are advantages to relying on type inference to have them usable in as wide a number of situations as possible.
This does not preclude the need for namespaces of some form, which is orthogonal to being OOP. Nor is the use of data structures discouraged. In fact, real use of FP languages depend heavily on data structures. If you look at the F# stack implemented in F Sharp Programming/Advanced Data Structures, you will find that it is not object-oriented.
In my mind, OOP is heavily associated with having methods that act on the state of the object mostly to mutate the object. In a pure FP context that is not needed nor desired.
A practical reason may be to be able to interact with OOP code, in much the same way F# works with .NET. Other than that however, are there any reasons? And what is the experience in the Haskell world, where programming is more pure FP?
I will appreciate any references to papers or counterfactual real world examples on the issue.
The disconnect you see is not of FP vs. OOP. It's mostly about immutability and mathematical formalisms vs. mutability and informal approaches.
First, let's dispense with the mutability issue: you can have FP with mutability and OOP with immutability just fine. Even more-functional-than-thou Haskell lets you play with mutable data all you want, you just have to be explicit about what is mutable and the order in which things happen; and efficiency concerns aside, almost any mutable object could construct and return a new, "updated" instance instead of changing its own internal state.
The bigger issue here is mathematical formalisms, in particular heavy use of algebraic data types in a language little removed from lambda calculus. You've tagged this with Haskell and F#, but realize that's only half of the functional programming universe; the Lisp family has a very different, much more freewheeling character compared to ML-style languages. Most OO systems in wide use today are very informal in nature--formalisms do exist for OO but they're not called out explicitly the way FP formalisms are in ML-style languages.
Many of the apparent conflicts simply disappear if you remove the formalism mismatch. Want to build a flexible, dynamic, ad-hoc OO system on top of a Lisp? Go ahead, it'll work just fine. Want to add a formalized, immutable OO system to an ML-style language? No problem, just don't expect it to play nicely with .NET or Java.
Now, you may be wondering, what is an appropriate formalism for OOP? Well, here's the punch line: In many ways, it's more function-centric than ML-style FP! I'll refer back to one of my favorite papers for what seems to be the key distinction: structured data like algebraic data types in ML-style languages provide a concrete representation of the data and the ability to define operations on it; objects provide a black-box abstraction over behavior and the ability to easily replace components.
There's a duality here that goes deeper than just FP vs. OOP: It's closely related to what some programming language theorists call the Expression Problem: With concrete data, you can easily add new operations that work with it, but changing the data's structure is more difficult. With objects you can easily add new data (e.g., new subclasses) but adding new operations is difficult (think adding a new abstract method to a base class with many descendants).
The reason why I say that OOP is more function-centric is that functions themselves represent a form of behavioral abstraction. In fact, you can simulate OO-style structure in something like Haskell by using records holding a bunch of functions as objects, letting the record type be an "interface" or "abstract base class" of sorts, and having functions that create records replace class constructors. So in that sense, OO languages use higher-order functions far, far more often than, say, Haskell would.
For an example of something like this type of design actually put to very nice use in Haskell, read the source for the graphics-drawingcombinators package, in particular the way that it uses an opaque record type containing functions and combines things only in terms of their behavior.
EDIT: A few final things I forgot to mention above.
If OO indeed makes extensive use of higher-order functions, it might at first seem that it should fit very naturally into a functional language such as Haskell. Unfortunately this isn't quite the case. It is true that objects as I described them (cf. the paper mentioned in the LtU link) fit just fine. in fact, the result is a more pure OO style than most OO languages, because "private members" are represented by values hidden by the closure used to construct the "object" and are inaccessible to anything other than the one specific instance itself. You don't get much more private than that!
What doesn't work very well in Haskell is subtyping. And, although I think inheritance and subtyping are all too often misused in OO languages, some form of subtyping is quite useful for being able to combine objects in flexible ways. Haskell lacks an inherent notion of subtyping, and hand-rolled replacements tend to be exceedingly clumsy to work with.
As an aside, most OO languages with static type systems make a complete hash of subtyping as well by being too lax with substitutability and not providing proper support for variance in method signatures. In fact, I think the only full-blown OO language that hasn't screwed it up completely, at least that I know of, is Scala (F# seemed to make too many concessions to .NET, though at least I don't think it makes any new mistakes). I have limited experience with many such languages, though, so I could definitely be wrong here.
On a Haskell-specific note, its "type classes" often look tempting to OO programmers, to which I say: Don't go there. Trying to implement OOP that way will only end in tears. Think of type classes as a replacement for overloaded functions/operators, not OOP.
As for Haskell, classes are less useful there because some OO features are more easily achieved in other ways.
Encapsulation or "data hiding" is frequently done through function closures or existential types, rather than private members. For example, here is a data type of random number generator with encapsulated state. The RNG contains a method to generate values and a seed value. Because the type 'seed' is encapsulated, the only thing you can do with it is pass it to the method.
data RNG a where RNG :: (seed -> (a, seed)) -> seed -> RNG a
Dynamic method dispatch in the context of parametric polymorphism or "generic programming" is provided by type classes (which are not OO classes). A type class is like an OO class's virtual method table. However, there's no data hiding. Type classes do not "belong" to a data type the way that class methods do.
data Coordinate = C Int Int
instance Eq Coordinate where C a b == C d e = a == b && d == e
Dynamic method dispatch in the context of subtyping polymorphism or "subclassing" is almost a translation of the class pattern in Haskell using records and functions.
-- An "abstract base class" with two "virtual methods"
data Object =
Object
{ draw :: Image -> IO ()
, translate :: Coord -> Object
}
-- A "subclass constructor"
circle center radius = Object draw_circle translate_circle
where
-- the "subclass methods"
translate_circle center radius offset = circle (center + offset) radius
draw_circle center radius image = ...
I think that there are several ways of understanding what OOP means. For me, it is not about encapsulating mutable state, but more about organizing and structuring programs. This aspect of OOP can be used perfectly fine in conjunction with FP concepts.
I believe that mixing the two concepts in F# is a very useful approach - you can associate immutable state with operations working on that state. You'll get the nice features of 'dot' completion for identifiers, the ability to easy use F# code from C#, etc., but you can still make your code perfectly functional. For example, you can write something like:
type GameWorld(characters) =
let calculateSomething character =
// ...
member x.Tick() =
let newCharacters = characters |> Seq.map calculateSomething
GameWorld(newCharacters)
In the beginning, people don't usually declare types in F# - you can start just by writing functions and later evolve your code to use them (when you better understand the domain and know what is the best way to structure code). The above example:
Is still purely functional (the state is a list of characters and it is not mutated)
It is object-oriented - the only unusual thing is that all methods return a new instance of "the world"
I've only recently come to really grasp the difference between static and dynamic typing, by starting off with C++, and moving into Python and JavaScript. What I don't understand is how a dynamically-typed language (e.g. Python) can be implemented on top of a statically-typed language (e.g. C). I seem to remember reading something about void pointers once, but I didn't really get it.
Every variable in the d-t language is represented as a struct { type, value }, where a value is union/another struct/pointer etc.
In C++ you can get similar ("similar") result if you, for example, create a base abstract class MyVariable and derived MyInt, MyString etc. You can, with some more work, use these vars like in dynamically typed language. (I don't know C++ very well, but I think you'll need to use friend operators functions to change a type of variables in runtime, or maybe not, whatever)
This result is archieved by the same thing, runtime type information, which strores info of actual type in the object
I won't recommend it, though :)
Basically, each "variable" of your dynamically typed language is represented by a structure in the statically typed language, which the data type being one of the fields. The operations on these dynamic data types (add, subtract, compare) are usually implemented by a virtual method table, which is for each data type a number of pointers to functions that implement the desired functionality in a type-specific way.
It's not. The dynamically typed language is implemented on top of a CPU architecture. As long as the CPU architecture is Turing complete, you can implement a static language on it, or a dynamic language, or something hybrid like the CLR/DLR of .NET. The important thing is that the Turing completeness of the CPU architecture is what enables or disables things, not the static nature of a programming language like C or C++.
In general, programming languages maintain Turing completeness, and therefore you can implement anything in any programming language. Of course some things are easier if the underlying tools support it, so it is not easy to implement an application that relies on a dynamic underpinning, in C or C++. That's why people put the effort into making a dynamic system that is programmable, like Python, so that you can implement the dynamic system once and suffer going through that extra effort only one time, then reuse it from the dynamic language layer.