My mother did her college thesis in Fortran, and now (over a decade later) needs to learn c++ for fluids simulations. She is able to understand all of the procedural programming, but no matter how hard I try to explain objects to her, it doesn’t stick. (I do a lot of work with Java, so I know how objects work) I think I might be explaining it in too high-level ways, so it isn’t really making sense to someone who’s never worked with them at all and grew up in the age of purely procedural programming.
Is there any simple way I can explain them to her that will help her understand?
4
Short answer: no.
Long answer: There’s no “simple way” because OOP is far from simple. Procedural programming is all about “variables” and “if then goto”. Everything else is syntactic sugar, but those four things are all of what procedural programming is about. Once you get them nothing can stop you.
OOP is a way to organize variables and pieces of code. How many patterns are there to define OOP? 25? 30? Even teachers who learned OOP from different languages and backgrounds don’t agree on its own definition, so … how can it be simple?
I don’t know how you came to that, but since your mother has a similar experience to mine, I can tell you how I came to that.
I was programming in C in a very large project. It was 1988. Many programmers organizing modules and libraries, with the difficulty of avoiding interference in other jobs and keeping a good segregation of duties.
We came to a “solution” that was to put all interrelated global data into structs, placing in those struct some function pointers where callbacks were required. We generalized in that way what we called io_mask
(sort of textual mode dialog boxes) and graphic_manager
etc. etc.
In 1996 It was very easy to discover that those structs were named “classes” and those function pointers replaced by member function and virtual functions, or with links to other objects (called behaviors) by other programmers who renewed that old project.
I started to understand OOP when I started to feel the need for it: segregation, polymorphism, and runtime defined behaviors.
Today I work with OOP, but I don’t think of it as a doctrine to serve: just a “common idiom” (set of …) that let us speak together without the need to provide long explanations and descriptions all the time. In fact, more a “convention” than anything else. After all, all OOP does is -again- “if then goto”: it just does it “multilayered”. Hence abstraction and idioms over idioms.
Ignore them. Until she doesn’t feel the need for them don’t even try to explain: she will feel them just as a complicated way to do simple things. And she is right… until what she does is -in fact- simple.
No one will think to “organize a desk” if there’re just four things on top. It make sense when the things on top start to interfere each other. That’s the time for OOP to come in.
You don’t need OOP to work with C++. The entire C++ standard library is not designed in terms of OOP (although it can cooperate with it), and C++ is not Java.
In all my experience the worst C++ teachers and C++ programmers are the ones who come from Java, teaching all their prejudice about everything is not OOP, denaturating a language like C++ that is not (just) for OOP.
Let me suggest a good book for those who want to approach C++: Accelerated C++: it will bring you into C++ idioms without pretending to follow a predefined doctrine.
3
An old friend claimed I had the shortest definition he knew of OO programming, and I’ve found that it works for some people (and not for others):
Object-oriented programming is data with an opinion.
You don’t move the chair, you ask the chair to move itself. You don’t sort the list, you ask it to sort itself (perhaps with a hint). Etc.
The idea is to get the person thinking differently about how things get done inside their program.
2
Tell her to think of objects like objects in the real world. For example the whole world can be a mix of object oriented programming(in C++) with some sort of functional programming(probably done in god’s language, Lisp).
Take an object, for example the lawn mower, it has a certain attributes, and it can do a certain thing. (object and class)
Then tell her about a better lawn mower which is an extension of the lawn mower you already have. Tell her its better but still builds on the same mechanism(inheritance).
Then tell her about yourself. Tell her you can sometimes become a lawn mowing expert but you’re actually a programmer and do it for a living. This is like you acting as two different entities at the same time. This is polymorphism.
By the time she gets this, tell her about how to implement these things in the language she has to learn(C++).
Then tell her, if she has to write a simulation of this world in the computer world, she will have to learn how to do it.
When she knows how to convert her thoughts of real world into program code. she would have learnt how to program in object oriented programming language.
5
I’ve gone from assembler and COBOL to Ruby.
What helped me initially was actually ignoring the concept of classes creating instances.
Just start with code. Have a class but just have class level methods. Within methods a lot of stuff is about parameters, variables, conditionals, arrays, strings, Booleans etc. This stuff should be familiar.
So at this point the class can be seen as just serving the purpose as a place to put all your related methods in. Call it a container or a library will be more familiar to her.
Obviously code has to be segmented to be manageable so you’ll have one of these each area. For example, for managing a set of utility programs on a pc, you might have a calculator class where you could put all the code for a calculator in one place. If you only have 1 calculator on your pc then class level methods are enough.
That’s a start.
ok now consider the fact that you want to open up multiple calculators and change how each one looks and where it is on the screen. So now you can’t just have a calculator method like ‘screen_location’ because you have several of them and each instance has its own location… each instance… ok, so we need instances.
Note: my terms are from ruby not c++ so you may need to translate.
I would explain it in two steps, or maybe four, depending on how much you like to split your concepts.
Step 1: Introduce her to structures. It’s a fairly small step from Fortran data types
to structures. Step 1a: make sure she understandard dynamic memory allocation and pointers.
Step 2: add procedures associated only with those structures. Step 2a: add inheritance based on building larger structures which “wrap” smaller structures.
To a Fortran programmer, the “wow” factor will be that it’s a lot for the compiler
to keep track of. Yup. That’s what compilers are for…
1
If she did her thesis a decade ago, she probably used Fortan 90 or 95, in which case the thing to is talk about it in relationship to derived data types. If it was long enough ago that she used Fortran 77, then introduce her to derived data types in Fortran 90 and then talk about it…
I wouldn’t go into polymorphism and inheritance, until after she has grasped encapsulation, as they can be viewed as special cases and extensions of encapsulation. I would probably start her on a language that either allows free functions or static classes.
0
Once she understands structures, I think the next key point will be to recognize that object-oriented programming serves as a means of confining the set of methods to which a thing may be passed, to the set of methods which could actually be applied to that thing.
In non-object-oriented programming, if one is using separate data types for a Tree and a LinkedList, one would have to use different methods for adding a node to each. Non-object-oriented languages would generally squawk if one tried to name both methods AddItem
, since any given name can only refer to one method, thus leading one to create method names like AddTreeItem
, AddLinkedListItem
, RemoveTreeItem
, etc. Such an approach works, but it’s a bit ugly. Conceptually, the methods AddTreeItem
and RemoveTreeItem
seem to belong together, but the names don’t sort that way. One could rewrite the names as TreeAddItem
, TreeRemoveItem
, LinkedListAddItem
, etc. but that would put a lot of “redundant noise” at the start of each method invocation. The vast majority of method calls in a typical program will have three essential pieces of information: (1) what section of the source code contains the method; (2) which of the methods in section is being used; (3) what piece of data is being acted upon? In many cases, the type of data being acted upon will be sufficient to identify which code section the method belongs to, so part (1) of the above is redundant. It’s easier to visually identify material at the start of a statement than material elsewhere, so a coding/naming style like TreeAddItem(myTree, whatever)
ends up putting the least useful piece of information in the prime spot.
By contrast, using object-oriented programming, one would effectively name methods as Tree.AddItem
, etc. and a statement like myTree.AddItem(whatever)
would cause a compiler to say, essentially, “Hmm… myTree
is of type Tree
, so this code should invoke Tree.AddItem()
. It’s not necessary to specify the Tree.
when calling AddItem
since the compiler knows the type of myTree
. Conceptually, a statement like myTree.AddItem(whatever)
is equivalent to Tree.AddItem(myTree, whatever)
, and some object-oriented languages may allow both forms as equivalent; in fact, most languages omit the first parameter from the function specification and instead have methods that are defined in a class like Tree
implicitly take a parameter of type Tree
, and assign it a name like this
, self
, or Me
.
Object-oriented programming languages often include a variety of additional features such as inheritance, virtual functions, etc. which are very useful in many applications, but even without those features the ability to group functions according to the things they operate upon is very useful.
Object-oriented programming—in the class-oriented sense relevant here—is about coupling a data representation with the code that manipulates it. It makes sense if the following things make sense:
-
Coupling: defining an operation alongside the data representation it works on
-
Late binding: choosing a combination of data representation and behaviour at runtime
-
Encapsulation: ensuring that data is valid by construction and won’t be later invalidated
That’s all. Like any technology, at its heart it’s simply a convenience, from which many developments have later followed. Once you understand the basics, the rest follows in time.
I would suggest downloading BlueJ, playing with it for 20 minutes then having her play with it for 20 minutes.
The way it visualizes classes, interfaces and inheritence is so obvious and intuitive that it really gives you an instant understanding as you implement something–anything.
It even shows you directly the difference between a class and an object
It won’t give any deep insights into OO design patterns, but it will give a fantastic overview of the concepts.
I would like to add my contribution as a reminder of the distinction between programming paradigms and programming languages that implement these paradigms.
So, in my opinion, the best way to explain object orientation with C++ to a F77 user, would be to proceed in a stepwise fashion:
First, introduce the user to the concept of object orientation in a familiar setting by showing her how to develop object-like structures in Fortran 77 – for instance, have a look at papers like B. Patton “Object-oriented Fortran 77 (a practitioner’s view)” SIGPLAN Fortran Forum 12, 2 (1993), pp. 23-24, and references therein.
Then, establish a correspondence between those structures and C++ classes and methods.
Finally, discuss additional features that C++ can provide to facilitate OO programming.
When I was first migrating to an object oriented language from my initial training in Pascal, the ‘.’ issue was the biggest hurdle for me too. It took me years to get over it.
It’s actually really unintuitive for a variable to belong to another variable, especially when you’re used to thinking of them as pointers. The stumbling block for me was:
- What does it mean for something that is basically a pointer, to have
a another pointer pointing to it, that resolves to a different thing
than the parent pointer?
The aha moment for me was when I realised that the top level pointer was basically just a namespace.
I’d suggest getting her to write a bunch of code which requires her to namespace her functions, ideally without using the dot notation to start with. Then get her to try and rewrite it using dot notation.
Doing that exercise a should get her over the initial “What witchcraft is this?” hurdle.
One key insight that has helped me in explaining before is the fact that you can have multiple instances of a class. Try to explain that in terms of “drawings” or “moulds” and “copies” and see if it leads anywhere.
1