I understand that abstraction is about taking something more concrete and making it more abstract. That something may be either a data structure or a procedure. For example:
- Data abstraction: A rectangle is an abstraction of a square. It concentrates on the fact a square has two pairs of opposite sides and it ignores the fact that adjacent sides of a square are equal.
- Procedural abstraction: The higher order function
map
is an abstraction of a procedure which performs some set of operations on a list of values to produce an entirely new list of values. It concentrates on the fact that the procedure loops through every item of the list in order to produce a new list and ignores the actual operations performed on every item of the list.
So my question is this: how is abstraction any different from generalization? I'm looking for answers primarily related to functional programming. However if there are parallels in object-oriented programming then I would like to learn about those as well.
Abstraction
Abstraction is specifying the framework and hiding the implementation level information. Concreteness will be built on top of the abstraction. It gives you a blueprint to follow to while implementing the details. Abstraction reduces the complexity by hiding low level details.
Example: A wire frame model of a car.
Generalization
Generalization uses a “is-a” relationship from a specialization to the generalization class. Common structure and behaviour are used from the specializtion to the generalized class. At a very broader level you can understand this as inheritance. Why I take the term inheritance is, you can relate this term very well. Generalization is also called a “Is-a” relationship.
Example: Consider there exists a class named Person. A student is a person. A faculty is a person. Therefore here the relationship between student and person, similarly faculty and person is generalization.
Not addressing credible / official source: an example in Scala
Having "Abstraction"
and "Generalization"
executing
leads to
Abstraction is usually about reducing complexity by eliminating unnecessary details. For example, an abstract class in OOP is a parent class that contains common features of its children but does not specify the exact functionality.
Generalization does not necessarily require to avoid details but rather to have some mechanism to allow for applying the same function to different argument. For instance, polymorphic types in functional programming languages allow you not to bother about the arguments, rather focus on the operation of the function. Similarly, in java you can have generic type which is an "umbrella" to all types while the function is the same.
Let me explain in the simplest manner possible.
"All pretty girls are female." is an abstraction.
"All pretty girls put on make-up." is a generalization.
Object:
Abstraction:
Generalization:
Example in Haskell:
The implementation of the selection sort by using priority queue with three different interfaces:
The code is also available via pastebin.
Worth noticing are the existential types. As @lukstafi already pointed out, abstraction is similar to existential quantifier and generalization is similar to universal quantifier. Observe that there is a non-trivial connection between the fact that ∀x.P(x) implies ∃x.P(x) (in a non-empty universe), and that there rarely is a generalization without abstraction (even c++-like overloaded functions form a kind of abstraction in some sense).
Credits: Portal cake by Solo. Dessert table by djttwo. The symbol was based on the Portal artwork.
A very interesting question indeed. I found this article on the topic, which concisely states that:
Lets take the old example of a system that manages books for a library. A book has tons of properties (number of pages, weight, font size(s), cover,...) but for the purpose of our library we may only need
We just abstracted from the real books in our library, and only took the properties that interested us in the context of our application.
Generalization on the other hand does not try to remove detail but to make functionality applicable to a wider (more generic) range of items. Generic containers are a very good example for that mindset: You wouldn't want to write an implementation of
StringList
,IntList
, and so on, which is why you'd rather write a generic List which applies to all types (likeList[T]
in Scala). Note that you haven't abstracted the list, because you didn't remove any details or operations, you just made them generically applicable to all your types.Round 2
@dtldarek's answer is really a very good illustration! Based on it, here's some code that might provide further clarification.
Remeber the
Book
I mentioned? Of course there are other things in a library that one can borrow (I'll call the set of all those objectsBorrowable
even though that probably isn't even a word :D):http://f.cl.ly/items/3z0f1S3g1h1m2u3c0l0g/diagram.png
All of these items will have an abstract representation in our database and business logic, probably similar to that of our
Book
. Additionally, we might define a trait that is common to allBorrowable
s:We could then write generalized logic that applies to all
Borrowable
s (at that point we don't care if its a book or a magazine):To summarize: We stored an abstract representation of all the books, magazines and DVDs in our database, because an exact representation is neither feasible nor necessary. We then went ahead and said
Thus we generalized the operation of borrowing an item, by defining all things that one can borrow as
Borrowable
s.