Functions are easy to understand even for someone without any programming experience, but with a fair math background. On the other hand, classes seem to be more difficult to grasp.
Let's say I want to make a class/function that calculates the age of a person given his/her birthday year and the current year. Should I create a class for this, or a function? Or is the choice dependant to the scenario?
P.S. I am working on Python, but I guess the question is generic.
Create a function. Functions do specific things, classes are specific things.
Classes often have methods, which are functions that are associated with a particular class, and do things associated with the thing that the class is - but if all you want is to do something, a function is all you need.
Essentially, a class is a way of grouping functions (as methods) and data (as properties) into a logical unit revolving around a certain kind of thing. If you don't need that grouping, there's no need to make a class.
Like what Amber says in her answer: create a function. In fact when you don't have to make classes if you have something like:
Here you just have a function encapsulate in a class. This just make the code less readable and less efficient. In fact the function
compute
can be written just like this:You should use classes only if you have more than 1 function to it and if keep a internal state (with attributes) has sense. Otherwise, if you want to regroup functions, just create a module in a new
.py
file.You might look this video (Youtube, about 30min), which explains my point. Jack Diederich shows why classes are evil in that case and why it's such a bad design, especially in things like API.
It's quite long but it's a must see
It depends on the scenario. If you only what to compute the age of a person, then use a function since you want to implement a single specific behaviour.
But if you want to create an object, that contains the date of birth of a person(and possibly other data), allows to modify it, then computing the age could be one of many operations related to the person and it would be sensible to use a class instead.
Classes provide a way to merge together some data and related operations. If you have only one operation on the data then using a function and passing the data as argument you obtain an equivalent behaviour, with less complex code.
Note that a class of the kind:
isn't really a class, it is only a (complicated)function. A legitimate class should always have at least two methods(without counting
__init__
).Classes (or rather their instances) are for representing things. Classes are used to define the operations supported by a particular class of objects (its instances). If your application needs to keep track of people, then
Person
is probably a class; the instances of this class represent particular people you are tracking.Functions are for calculating things. They receive inputs and produce an output and/or have effects.
Classes and functions aren't really alternatives, as they're not for the same things. It doesn't really make sense to consider making a class to "calculate the age of a person given his/her birthday year and the current year". You may or may not have classes to represent any of the concepts of
Person
,Age
,Year
, and/orBirthday
. But even ifAge
is a class, it shouldn't be thought of as calculating a person's age; rather the calculation of a person's age results in an instance of theAge
class.If you are modelling people in your application and you have a
Person
class, it may make sense to make the age calculation be a method of thePerson
class. A method is basically a function which is defined as part of a class; this is how you "define the operations supported by a particular class of objects" as I mentioned earlier.So you could create a method on your person class for calculating the age of the person (it would probably retrieve the birthday year from the person object and receive the current year as a parameter). But the calculation is still done by a function (just a function that happens to be a method on a class).
Or you could simply create a stand-alone function that receives arguments (either a person object from which to retrieve a birth year, or simply the birth year itself). As you note, this is much simpler if you don't already have a class where this method naturally belongs! You should never create a class simply to hold an operation; if that's all there is to the class then the operation should just be a stand-alone function.
Before answering your question:
If you do not have a
Person
class, first you must consider whether you want to create aPerson
class. Do you plan to reuse the concept of aPerson
very often? If so, you should create aPerson
class. (You have access to this data in the form of a passed-in variable and you don't care about being messy and sloppy.)To answer your question:
You have access to their birthyear, so in that case you likely have a
Person
class with asomeperson.birthdate
field. In that case, you have to ask yourself, issomeperson.age
a value that is reusable?The answer is yes. We often care about age more than the birthdate, so if the birthdate is a field, age should definitely be a derived field. (A case where we would not do this: if we were calculating values like
someperson.chanceIsFemale
orsomeperson.positionToDisplayInGrid
or other irrelevant values, we would not extend thePerson
class; you just ask yourself, "Would another program care about the fields I am thinking of extending the class with?" The answer to that question will determine if you extend the original class, or make a function (or your own class likePersonAnalysisData
or something).)Never create classes. At least the OOP kind of classes in Python being discussed.
Consider this simplistic class:
vs this namedtuple version:
The namedtuple approach is better because:
inheritance
adds complexity, and hides complexity.I can't see a single advantage to using OOP classes. Obviously, if you are used to OOP, or you have to interface with code that requires classes like Django.
BTW, most other languages have some record type feature like namedtuples. Scala, for example, has case classes. This logic applies equally there.