There are a lot of buzzwords in the programming industry describing approaches to how to write code. Of course, none of these paradigms are any specific way of solving any specific problem; they're extremely broad, general ways of thinking about problems. And not all of them are exclusive. I also don't claim that the ones I talk about here are the only ones, just some commonly discussed ones that I've experienced.
Procedural programming means thinking about a program as a sequence of steps that completely describe what to do. In some sense, everything boils down to procedural programming because everything gets compiled to processor instructions which are inherently procedural. But this way of thinking about programming, while it's sort of inherently true, isn't normally the best way to think about a complicated problem.
The idea of object-oriented programming, at least as I understand it (this one is by far the hardest to pin down and the explanations other people give are spectacularly dodgy), is to think about a program as a model of objects interacting. An object here is a data structure that represents something concrete; and a class in object-oriented terminology is a template for objects.
For example, to implement a typical JPRG-like battle system, you would have a Character class to represent a character in a battle. A Character object would have certain attributes, like life, strength, mana; and would also have certain methods, which are like procedures that are attached to a particular object because they deal with that object.
Depending on how your damage calculation works, the Character class might have a
take_damage method that's
called whenever they get attacked. This method would internally account for whatever resistances or on-hit effects the
character might have.
There are a lot of potential benefits to thinking this way; one of them is that it helps keep everything related to a specific object clearly attached to that object. Code in the main battle loop would never have to worry about how damage is calculated, only about the steps of a round (get each character's action; then call the method for each one in sequence).
Object-oriented programming is the topic of some fierce debate, where a lot of people think it's wonderful and other people think it's a false savior and it's actually a horrible way of thinking that just leads to "spaghetti code" in the end. I came to an epiphany some time ago; I think firstly that OOP is too vaguely defined to be said to be "good" or "bad", but depending on how you define it there are some bad practices associated with it and half of the benefits claimed for "inheritance" are actually benefits of interfaces, not classes.
Event-driven programming is a way of thinking about programming that mainly applies to interactive applications. To understand it you kind of need to understand how procedural programming approaches such a thing.
If you were to write a program with an interface, say something like a web application, in a procedural paradigm, you would have a loop that the program spent most of its time in. The loop would be basically, in pseudocode:
> Check if there's been any input from the mouse or keyboard or whatever input device. > Get an "event" data structure describing that input. > Look at the event, and see what action needs to happen based on it, if any. > Take the necessary action. > Update the display.
That's some extremely ugly logic to be all in the mainloop. Programs written like that quickly become hard to follow and therefore hard to avoid bugs in.
Event-driven programming thinks about a user interface by making this "mainloop" a core concept instead of something you write manually. You set up the interface elements as objects or something, declare how each one should respond to input, and then call the mainloop function, which is just a single line from your code's perspective, and all the steps of the mainloop are encapsulated so you don't have to think about them.
Event-driven programming is heavily beneficial in its intended arena because this is the natural way to think about
that type of problem. The program's code is centered on describing the interface and how it behaves rather than how
that behavior is achieved. Usually you specify behavior with "callback" functions. For example you might have a
Button object and you'd give it a method
handleClick, which the mainloop calls whenever
the button is clicked on.
By encapsulating the mainloop, event-driven programming saves you from having to worry about bugs like the display not updating or forgetting to pass a click event to the element that was clicked. If you're thinking about the internals of how the mainloop works, then You're Doing It Wrong.
it's designed with that in mind, and so a lot of stuff is accomplished with
addEventListener and stuff. In
browser and is started on page load. In a language that wasn't specifically designed for this, like if you're using
Python or C with GTK (a GUI library that's both object-oriented and event-driven), you'll
still be doing the setup somewhat imperatively and calling the mainloop manually, but it can still be really helpful
over doing this in a completely imperative way.
Functional programming means thinking about code as a transformation of data rather than steps to be executed. In a pure functional language like Haskell, you think about algorithms by describing the output you want in terms of the input, rather than directly describing how to produce it.
Functional progarmming involves preventing any function from changing anything other than its return values or making them depend on anything other than its inputs. It can seem at times like an enormous inconvenience, but in the long run keeping as many things as deterministic as possible and the the I/O and non-deterministic aspects as isolated as possible can go an enormous way toward making it easier to keep track of the logic and avoid bugs.
One example of functional programming is the
functions that a lot of languages have. If you wanted to take a list of items and apply some transformation to
each of them, here's how you'd do it procedurally (I'll use Python as the example language, so that there won't
be a red herring difference in verbosity):
def get_sqroots(nums): sqroots =  for num im nums: sqroots.append(num ** 0.5) return sqroots
That's not bad, but if you're not used to this whole pattern of for loops and iterating it takes a second to figure out what's going on. We're building a new list and then adding in each new value. Despite how this is a task that really can and should be described in one thought, we're instead describing how we're getting there instead of just what we're achieving.
Here's a functional way of approaching the problem:
def get_sqroots(nums): return map(lambda x: x ** 0.5, nums)
(If you don't know,
lambda declares an anoymous function.
lambda x: x ** 0.5 is
equivalent to passing in a function that takes
x and returns
x ** 0.5.)
This means, "map each element in nums to the result of putting that num into this function, and return the
resulting list". (Technically Python's
map returns a generator, which is a close to strictly
better way of doing this; the exact parallel to the procedural
get_sqroots would be
return list(map(lambda x: x ** 0.5, nums)), or, written with the kickass generator expressions
return [num ** 0.5 for num in nums].)
filter is similar: you pass it a function and a sequence and it returns the sequence with only
the elements for which the function returns True. And the idea of
reduce (to get
reduce in Python 3 you
import functools) is to pass a function and a sequence and you get the sequence reduced
to a single element by repeatedly applying the function. For example you could
reduce a list of
integers via the
+ function (in Python you'd have to be a little more verbose and pass it
lambda x, y: x+y Although
Python has a built-in shortcut
sum(nums) for this particular reducing function) to get the sum.
(Functional languages like Haskell can do that simpler by just passing
(+) to signify the plus
Functional approaches can make things a lot simpler for things that are easily described as a transformation of data. How pure functional languages deal with things like IO is a far more complicated story.
Declarative programming is a paradigm closely related to functional programming in that in focuses on describing data and its relationships rather than steps to be executed. I'm not certain it's fair to say that the two are actually different, but I'd say functional programming is more about relationships between data and declarative programming is more about declaring data in a vacuum. Perhaps relatedly functional programming tends to describe complete languages, but I've never heard a full programming language called declarative.
At any rate, HTML is an example of declarative progamming: it doesn't tell the browser what to do, it describes - declares - the content on the page. What would HTML be like if it were implemented imperatively?
document.add(header_element("My Document")) container = create(div_element) container.set_style("color", "green") container.add(paragraph_element("Text goes here")) container.add(link_element("Check out this cool website")) document.add(container)
It would look something like that. Isn't that disgusting and unreadable?
And deep under the hood, some series of steps like this is getting executed, somewhere in the browser's rendering engine (which is probably written in C). But this way the browser engine developers can focus on making a system that converts HTML to content on the screen correctly while webmasters can focus on writing HTML that just describes their content. No one has to actually write code that looks like the above.