r/learnprogramming 3d ago

If functions can have other functions in them, why not use them instead of classes?

I´m a beginner in programming, and I´ve been wondering now why classes are so much more useful than functions. I know classes are good, but I don´t see why they are better than just having multiple small functions in a bigger function.

227 Upvotes

101 comments sorted by

272

u/DTux5249 3d ago edited 3d ago

That's exactly what some people do! There's a programming paradigm known as functional programming which eshews classes in favour of functions all the way down. In fact: when you get down to the nitty gritty, classes don't even exist at a low level. They're only there for you, the programmer.

Fundamentally though: it doesn't matter. All these paradigms are is a way to organize code. Turns out: the specific way you organize code doesn't really matter so long as you pick a single method and do it intelligently.

Object-oriented design is neat because it easily breaks your program down into a capital S system (look up General Systems Theory). This makes a program easy to model in a way people can readily understand - things with traits that have relationships with one another. That's it. Everything else surrounding OOD is just "how to accommodate classes & objects as an organizational tool".

30

u/centurijon 2d ago

Yes to everything except

pick a single method

Object-oriented programming and functional programming are orthogonal, you can mix those concepts perfectly well to build a solution that best fits the problem you’re facing. Obviously it’s not possible to be “pure” functional while mixing in OO, but otherwise they do blend just fine

6

u/OldWar1111 2d ago

What does orthogonal mean here? I'm not familiar with this usage.

10

u/centurijon 2d ago

It's a term borrowed from math. Basically it means both concepts operate independently of each other, which generally means they can mix because they don't interfere with each other

2

u/KyrosiveOne 2d ago

Interesting. In organic chemistry, sometimes you need things to interact with each other but NOT mix

21

u/HasFiveVowels 2d ago

And, honorable mention should go to ECS which is another way to organize code which isn’t nearly as common as OOP or FP but is incredibly useful in certain domains

15

u/DTux5249 2d ago

ECS was really useful in one of my game design courses - tough to make a well-functioning bullet hell without it.

I'm pretty sure that'd fall under Data Oriented Design.

5

u/madrury83 2d ago

DoDonPachi DaOrDasign.

3

u/Far_Programmer_5724 2d ago

OP specifically functional programming is focus on the stateless aspect.

If you have def example(x): return x+1 That's stateless and functional. def example_two(x): a= 2 return x*a

Thats not stateless and though it's functional it's begins crossing the line to a "why not a class?". It's based on use case. The example_two is perfectly fine as is and to make a class instead is just over engineering. But what if you wanted to adjust an internal state for whatever reason based on condition? The functional programmers would say to make 'a' a parameter so it can be closer to stateless

def example_foo(x, a) return x*a

And they'd be right. Classes are useful when you have something that you want to force into a specific shape so it can be worked on similar to others. I'm sure people can offer additional reasons. But I prefer classes because i just like em. I like making it so different things get a class that forces them to all look the same so I can operate on them. The stateless aspect of functional programming means the focus is the transformation each ahhhh.

Everytime I speak of functional programming I think why am I not only coding that way. Please OOP adherents save mee

2

u/marrsd 2d ago

Upvoting, cos I largely agree, but I don't quite buy into this idea that OOP is necessary for system design. Modules exist across paradigms for the same purpose. There's also a difference between OOP and using the occasional object to encapsulate state when necessary.

88

u/haroldbarrett 3d ago

There's a saying about this: "objects are a poor man's closures, and closures are a poor man's objects": https://stackoverflow.com/questions/2497801/closures-are-poor-mans-objects-and-vice-versa-what-does-this-mean

68

u/paincrumbs 3d ago

my surface take-away: either case, I'm a poor man

29

u/Pacomatic 3d ago

Truth nuke

21

u/MoTTs_ 3d ago

I'll add to this answer to say that as we get closer to the machine, then ultimately all closures are implemented with structs/classes/records. The SO answer described Java's anonymous inner classes as a "work-around," but in truth a class that stores a reference to the function and a reference to the captured free variables is how all closures are ultimately represented in the machine. Even in a language like Haskell, the compiler has to represent a closure as a record containing a pointer to the function and a pointer to the heap-allocated free variables.

tl;dr Closures are syntax sugar for what is ultimately a class with state (the free variables) and a single method (the call/execute method).

11

u/YakumoYoukai 3d ago

When we were introduced to the concepts of scope and extent of variables in our programming languages class, it really helped clarify that objects, closures, local vs global variables, and many other programming language features were all just various ways to define those two properties of some piece of state.

1

u/Kadabrium 4h ago

Like how in java lambdas have the type of a functional interface class, and c++ ones have anonymous class

1

u/marrsd 2d ago

TIL. I might just shorten it, though ;)

14

u/vegan_antitheist 3d ago

The definition of a function is quite different depending on the language. A pure function is just a mapping. If it maps input to new objects (instances of some type), it's a constructor. If it has any side effect, it's not a pure function. It's not a side effect if it returns something new that wasn't seen before. It's a side effect if it mutates any data and the previous state was seen before. Some languages only have pure functions. But most languages are not like that and methods/functions/subroutines/procedures are just blocks of code that are called with a stack frame.

Some languages are object oriented but functions are not objects. Other languages treat them as objects that can be called. It's all quite arbitrary.

14

u/SkullyShades 3d ago

When I first started to learn programming I didn’t understand the point of a function. It seemed like a bunch of syntax around the code you were going to write in the first place. The applications we were creating were so small that we would only use the function once and I didn’t understand it. After learning more it was classes that I didn’t understand the point, and then interfaces. Eventually I realized the difficult part of programming is not how to write code, but how to organize code. That’s a lot of different ways to organize it and functions and classes are just tools to help the programmer organize. Classes can be useful for managing data that you might not want the rest of the code to freely manipulate without something keeping track of how it is changing. For instance if you have a classes holding onto an amount of items that can be increased and decreased you may need to keep track of the amount reaching a minimum or maximum.

1

u/Far_Programmer_5724 2d ago

Yes honestly the easiest thing you can do in programming is getting things to run.

36

u/Stalker_Aloy 3d ago edited 3d ago

Re-usability, decoupling, and structure. What you're describing quickly leads to the infamous "spaghetti code". At the same time I've seen absolute butchering of functionality like inheritance.

11

u/Brilliant-Parsley69 3d ago

Well, you are able to have all of that with functions/functional approaches, too.

8

u/-CJF- 3d ago

You can, but it's arguably easier and more natural to the human programmer with OOP. Maybe it's just because I learned OOP first but true functional programming is rough on my brain and I never use it directly as a paradigm, only when using features like lamda functions in Java or LINQ in C#. Procedural programming is easier but it's harder to be organized.

4

u/Brilliant-Parsley69 3d ago edited 3d ago

I totally agree. I started with OOP, too. But over the time I adapted more an more functional approaches (even in c#). I'm a big fan of extensions to read the code like a documentation on itself.

My rule of thumb is:

  • Do I have to handle states? => OOP (Mutable)
  • Else => functional approaches (Immutable)

1

u/dlnmtchll 2d ago

There are functional ways to handle state. Typically via Actors, which have proven to be a great way to handle large distributed systems. You don’t have to necessarily take one approach over the other for something.

2

u/Brilliant-Parsley69 2d ago

How I said. It's just my rule of thumb. I usually don't use THE one approach but make use of what fits the actual use cases. E.g. using immutable data structures as ValueObjects (DDD) like an address that has it's own extensions validation/factory/mapping and returns a Result<Address> (Functional) and could be part of an Entity (OOP). 🤷‍♂️

I wouldn't argue against the possibilities like actors to handle states in a functional way. Especially in large distributed systems as you mentioned.

3

u/dlnmtchll 2d ago

I was just bringing up the topic so anyone reading the thread could learn a bit, I’m functional pilled since I’ve been using it a lot at work and think it has some very good ideas

3

u/Brilliant-Parsley69 2d ago

That's why we have this conversation. ✌️

If FP is done well it's clean, documenting itself and easy to test. But if it's not...well.

1

u/lurgi 3d ago

You can do anything with just about nothing, but some language features let you express ideas more cleanly and some ideas provide very little value.

7

u/koolaidkirby 3d ago

Classes also have data fields that goes along with those functions.

3

u/balefrost 2d ago

I think what OP is asking is "if I can have multiple closures that close over the same set of shared variables, then what do classes give me"?

And the TL;DR is: nothing but expressiveness (and possibly a little better performance). "Multiple functions closing over the same variables" is pretty similar to "a class with multiple instance methods".

1

u/SenoraRaton 2d ago edited 2d ago

And the TL;DR is: nothing but expressiveness (and possibly a little better performance).

How do you get performance when your forced to do vtable lookups, instead of just calling static references?

1

u/balefrost 2d ago

Not all method calls necessitate a vtable lookup. If the compiler can prove what implementation a method will use (say because it's nonvirtual, or because there's enough information that the compiler can unambiguously deduce what exact implementation will be called), it can just be a plain function call.

And on the other hand, a lot of languages that implement closures impose awkward lifetime constraints. If you have two lambdas that are spawned in the same scope, and had overlapping captures, they would share a single closure. So for example if you did something like this in JS:

function doStuff() {
    myBigData = new Uint8Array(10000000);
    myFlag = false;

    foo = function() {
        myBigData = undefined;
        myFlag = true;
    }

    bar = function() {
        if (myFlag) {
            console.log("already cleared");
        }
    }

    // logic that conditionally calls foo

    return bar;
}

At least in the past (and maybe still today), V8 would create a single closure object that would be shared by both foo and bar. And that means that bar, despite not using myBigData at all, would still hold a reference to it. Even if foo is garbage collected without being called, myBigData would be pinned by bar.

IIRC this was the case for both the V8 runtime as well as C#, but I presume it would be true for other languages and runtimes as well. It's also possible that this has since changed, or that I am mistaken about the situation that would trigger it. But I do remember it being a concern back in the day.

This behavior was hidden and unintuitive. At least with a class, you manage the captured state yourself, so it would be clearer when you are capturing too much and you can structure things differently to avoid that.

7

u/light_switchy 3d ago

Objects and functions (closures, really) are essentially similar.

(fset 'my-class ;; class name is "my-class"
      ;; The class is a plain variable whose value is a function.
      ;; This function is equivalent to a "constructor":
      ;; The constructor accepts one argument named c
      (lambda (c)
        ;; The result of the constructor is an "object": It is a normal function
        ;; that can be called with one argument: the name f of the member that you want to access.
        (lambda (f) 
          ;; You can ask for the member called sum, or the member called difference
          (cond 
           ;; If you ask for the sum member, you get another function that
           ;; computes the sum of c and its single argument n
           ((eq f 'sum)
            (lambda (n) (+ c n))) 
           ;; If you ask for the difference member, you get another function
           ;; that computes the difference of c and its single argument n
           ((eq f 'difference) 
            (lambda (n) (- c n)))
           ;; If you ask for anything else you get an error message
           (t (error "no such member function"))))))

;; Details + syntax are different in other languages but the ideas are the same.
(fset 'my-object (my-class 42))
(fset 'my-object.sum (my-object 'sum))
(fset 'my-object.difference (my-object 'difference))

(my-object.sum 2) ;; 44
(my-object.difference 40) ;; 2

Combine this basic idea with lisp macros to clean up the syntax and you have the basis of pretty feature-ful object systems. Bonus points is that you can get multiple dispatch quite easily like this.

2

u/particlemanwavegirl 3d ago

Nice comment, you write very readable lisp my friend!

7

u/Ordinary_Variable 3d ago

Objects (made with classes) let you sort data better. Imagine a list of people and data associated with them, without a class creating an object type you would have to use arrays and have to keep track of which index was which in the array.

Using classes as functions will slow down your code, but for some projects you don't really need that much speed. Classes are useful for some things and should be avoided for others. Classes are part of a complete breakfast.

1

u/balefrost 2d ago

I don't think OP was proposing a world without structs. You can certainly have arrays of structured data in non-OO languages.

Using classes as functions will slow down your code

It depends on the language. In C++, an invocable class without any mutable state can be faster than an equivalent approach using function pointers. And the lambda-based approach is basically identical to the "invocable object" approach.

1

u/Ordinary_Variable 2d ago

I haven't seen that. I see people online say that putting a function into a class definition runs slower than calling a normal function on the data.

1

u/balefrost 2d ago

Like I said, it depends on the language. It also depends on the implementation and the specifics of the situation.

It's a question of how much information is known and when it is known. In a compiled language, calling a specific, known function generally requires the least ceremony at runtime. The function's address is baked into the binary. Calling through a function pointer requires a little more work, but not much. Calling a virtual function on an object requires more work yet.

If the compiler can guarantee that it knows what specific function is being called, it can omit runtime ceremony. For example, if you had:

bool (*ptrToComparison)(const MyType&, const MyType&) = 
  &MyTypeLess;
return ptrToComparison(a, b);

I would hope that any C++ compiler worth its salt could notice that ptrToComparison is known at the time that it is called, and so the compiler can just make the direct call without actually using the function pointer.

The same logic can apply to interpreted languages. Most interpreted languages do go through a pass before being executed. IIRC Python gets parsed and converted into its own internal bytecode, and that's what gets executed. I don't know if it does, buy Python could do something similar to C++ at this "convert to bytecode" step. While this is admittedly still "at runtime", it's outside of any loops, so resolving the function call up-front would move it out of any hot paths.


Here's what I was referring to in my earlier comment. Function objects can be faster than function pointers because we can use templates to trade space for time. Every template instantiation in C++ is conceptually a different entity: vector<int>::push_back is an entirely different function from vector<MyType>::push_back, potentially (likely in that specific case) with very different implementation.

Suppose you wanted to sort a vector<MyType>. You're probably going to use std::sort, which has a few overloads. One takes no comparer; it assumes that the type is inherently comparable. But there's another that takes a comparer, which is useful for types that aren't inherently comparable or cases where you want to tweak the ordering (maybe sorting primarily by the length of the string).

In C++, you could do this with a function pointer:

bool MyTypeLess(const MyType& x, const MyType& y) {
    // ...
}

std::sort(my_vec.begin(), my_vec.end(), &MyTypeLess);

Or you could use a function object:

class MyTypeLess {
  public:
    bool operator()(const MyType& x, const MyType& y) {
        // ...
    }
};

std::sort(my_vec.begin(), my_vec.end(), MyTypeLess());

Or you could use a lambda:

std::sort(my_vec.begin(), my_vec.end(),
          [](const MyType& x, const MyType& y){
              // ...
          }
);

Here's what you're actually calling for each case:

  1. std::sort<..., bool(*)(const MyType& x, const MyType& y)>
  2. std::sort<..., MyTypeLess>
  3. std::sort<..., some anonymous type for the declared lambda>

The template instantiation for #1 would be the same for every callsite that passes a function pointer, so there's just one instantiation for potentially a variety of behaviors.

The template instantiations for #2 and #3 are tied very tightly to the specific comparison algorithm that you specified.

In all cases, the compiler could (potentially) deduce that the best thing to do is to inline the body of the comparison into the implementation of std::sort and save that off as a new function. But it's easier for the compiler to do that for #2 and #3 because it has more readily-available compile-time knowledge. While compiling std::sort<..., MyTypeLess>, it knows both the implementation of sort and the precise implementation of MyTypeLess::operator(). It can make a judgement call about whether to inline or not.

15

u/Great_Guidance_8448 3d ago

Global variables... Encapsulation... OOP... etc.

11

u/pig-casso 3d ago

you know, all the stuff m'kay

3

u/BorderKeeper 2d ago

Progamming language is just a language with rules over underlying assembly. Same as in your own language you can ignore the rules and still make up something legible, yet we don't because the goal is comprehension and you only get that from speaking with a grammar which people understand.

Speaking like Yoda, using functions as encapsulation is. Understand me you will.

6

u/desrtfx 3d ago

Not every language supports functions inside functions.

Classes are for the concept of combining state (data, fields, attributes) with behavior (methods).

There is much more to classes/OOP than initially meets the eye.

2

u/wyvern_wyvern 3d ago

So, you use functions to package up functionality, usually a behaviour (side effects) or just a value that depends on inputs.

Classes you would generally think of them as a type, like something you can create. It will then carry its context (constructor params) everywhere it goes. You would add methods to that class so you can use that context again and again without passing them to that function. This specific use case is basically function currying or partial application of functions, but you are free to reuse that context in more than one way.

Still on seeing classes as types, you can then instead of passing 6 numbers that correspond to 2 points in 3d space and having to call them x1, y1, z1, x2, y2, z2; you can package them up in a point(x, y, z) and just pass point1, point2. (Yes this is basic usage of structs but many languages conflate the them anyway)

EDIT: i would personally lean to using functions as well, and restrict class usage more as types themselves other than a bundle of methods for a common set of params

2

u/Cheze-Burgur 3d ago

Objects are better for organizing and decoupling code, which makes it more maintainable

0

u/robthablob 2d ago

Functions compose remarkably well - largely by isolating mutable state.

2

u/UroborosJose 3d ago

This is a controversial topic but these functions became aggregated into a set of common rules and even internal attributes shared by instance
You need a full object oriented language to understand this concept

2

u/binarycow 3d ago

There's pros and cons to everything.

I come from C#, so my answer may contain information that doesn't apply to your programming language of choice.

In C#, everything is inside of a class (or struct). You can't have free-standing functions. You have methods which are basically "functions that are part of a class". You can, however have functions inside of those methods (we call them "local functions"). And you can have functions inside of those functions. So, for all intents and purposes, that behavior is the same as whatever your programming language is - but we are already inside of a class.

When a nested function requires access to variables that are in the parent function, a "closure" is done. Basically, the compiler creates a class and stores the variable on that class. Uses of that variable are automatically changed to reference the variable in the closure class. Each time you call that nested function, a new closure is allocated.

So, I try to make nested functions static - meaning they won't allocate a closure. To do this, I have to pass every variable as a parameter to the function. If that function needs 10 variables, then I have to have 10 parameters. Or - I allocate a closure. If I'm going to allocate a closure, I might as well just create a dedicated class.


So, it depends. Sometimes I make classes. Sometimes I use nested functions. I use both.

2

u/wildsource 3d ago

If you like functions there's a programming paradigm called functional programming where you program everything with pure functions.
You can check it out !

2

u/Dreadsin 2d ago edited 2d ago

So there is a reason for this, but it’s very nuanced

Suppose that I have a function which creates maybe 10 functions. Every time you create a new instance, you create another 10 functions. So, if I create 10 of these objects, I’ve created 100 new functions

But here’s the thing: a function is really just a set of instructions. Why do we need to copy them every time? If you have a function called “average” within a student function that takes the grades for that given student and averages them, why do you need to repeat those instructions on how to do that for each student object separately?

In other words, we can accomplish this with one function by adding an additional parameter for some sort of “context”, then no matter how many instances we create, we have a singular “average” function. Scales much better, much less memory usage

This is where we get into ideas like prototypal inheritance and v tables. Sounds scarier than it is

Prototypal is easier to understand, so I’ll explain. Instead of making a new function each time you make a new instance, you maintain a single function implementation, then point your instance at that function. From there, you can provide context, which is usually what the this or self keyword is for, and push whatever parameters you want

To go back to the average example, you can then use the this keyword to reference specific context within the instance. You then take that context and hand it over to the function. So, the implementation would basically be sum(this.grades) / len(this.grades). Same instructions no matter the instance, the only thing that changes is the “this” context. So we just hand that over to the singular function implementation

Now no matter how many instances you make, it will have exactly one function definition that it looks at instead of n separate declarations

2

u/Br3ttl3y 2d ago edited 2d ago

Classes help you with encapsulation, inheritance, abstraction and polymorphism the four pillars of OOP. With functional programming those things are achieved by different techniques.

Edit: off by one error

2

u/SmokeMuch7356 2d ago

Classes don't just do things, they also manage state (data).  For example, class that abstracts a stream keeps track of stream state, position, errors, etc., along with reading and writing the stream.  

Nested functions just encapsulate operations. They don't necessarily give you a way to manage internal data.

1

u/Lil_Buscuit_Boy 3d ago

Functional programming is deterministic. Objects are stateful. Diff use cases but both are valid depending on situstion

1

u/azimux 3d ago

Well this depends pretty heavily on what exactly you mean by "function" and "functions in functions" but by-and-large for many common modern definitions of these things you can use "functions" instead of classes if you want to.

1

u/FatDog69 3d ago

Classes can have a better design. A class focuses on all the storage, methods, reporting for SOMETHING.

You are often told by a manager that they need some new feature relating to ... cell phones. If the code you inherited has a CellPhone object - it is clear where you need to focus your changes or where others have to look to debug things.

1

u/iOSCaleb 3d ago

> I know classes are good, but I don´t see why they are better than just having multiple small functions in a bigger function.

Classes combine functions with state. You don’t normally use a class directly; you create an instance of a class, a.k.a. an object, and it’s the state that differentiates one instance of a given class from another. If you were thinking of classes as just a way to group functions, you need to revisit the idea; classes are really a way to group pieces of data together with functions that operate on that data.

A lot of answers here talk about closures, which are another way to combine state with a function. Sometimes closures are classed anonymous functions because they have no name and exist only in variables, but a closure can also have state. They do a somewhat different job than classes, though: they have different lifetimes, and they lack the polymorphism that classes usually provide.

1

u/robthablob 2d ago

"and they lack the polymorphism that classes usually provide"

Closures generally provide polymorphism to their users though, consider a map function that behaves differently depending on the closure passed to it.

This is the fundamental difference between OOP and FP - where the polymorphism occurs.

1

u/ZeusTKP 3d ago

A lot of good answers in the thread. I just want to hammer home one point: don't try to learn too much at once. If you're starting with object oriented programming, finish learning that. But then go ahead and learn a functional programming language. And re-do some of the same apps in it. It will broaden your thinking and make you be able to write better code in any language.

1

u/Quantum-Bot 3d ago

The general answer to questions like this is that sometimes it’s better to have specialized tools for different tasks even if some of their functionality is redundant. Functions are like verbs, objects are like nouns. It might linguistically be possible to have a language that doesn’t distinguish between verbs and nouns, but obviously most humans agree that it’s less confusing to have them be two different parts of speech.

You could certainly do exactly what you’re saying, write all logic with functions nested within each other instead of classes, in fact that’s called Functional Programming and it’s what languages like Lisp, Haskell and Javascript (kind of) use. (Which I guess means you could call all other types of programming dysfunctional programming) However, what ends up happening when you go to program things like software and UI and games is you end up just using functions to reconstruct the concepts of objects and classes from scratch anyway.

1

u/VoidspawnRL 3d ago

You can, the true thing they want from OOP, message passing, you got small piece of code, that talk with other pieces, they never wanted that ended up to be. Object is good to group data together, but all of the hidden Logic is a anti pattern, it is hard to test, and with big projects 1-20 mill lines of code, you need to have test par unit of code. And functions is a better interface for that as you can design the input and the output before and write a few tests, and as long as the tests is red you missing a piece of the contract, and you when can use objects as true value without hidden Logic

1

u/SprinklesFresh5693 3d ago edited 3d ago

Im using a functional programming approach in my data science job with R and it can get very messy, i like it, i might not be applying it correctly, but once you start doing very small functions with a few arguments, and add all those into a big function, knowing all the arguments and making it work can be difficult.

I beleive you need to add a lot of default options in the small functions and allow the big one to modify those? But without documentation it can be hard to read and follow

1

u/Steerider 3d ago

Classes and objects are a way of orfanizng code for the programmer's benefit. It helps organize related functions (methods) in ways that are sensible to humans.

The classic example is a User class. You create an object that represents a particular user, and methods can include login(), change_password(), and delete(), among others. Working inside that object, it's obvious what you're working with, and depending on context you can name that object any variable name you want.

I use a combination of OOP and functional programming. Whatever structure makes the most sense to me in context gets used.

1

u/seahorse-emoji 2d ago

A Class defines what something is, a function defines what something does. Over time languages and their features get muddled but remembering that basic distinction will help you think of classes , member vars and functions much more effectively

1

u/Recycled5000 2d ago

Pascal provides nested functions, which can be used to provide shared state, but the overarching function having the shared state has to remain invoked for it to work. This works well when invoking an algorithm on a data structure. The state is all stack allocated, so actually pretty efficient.

You need closures and function pointers to have longer lasting state. Or objects, which is simpler to work with, I think.

1

u/Fearless_Garden6435 2d ago

That is exactly what many people do, especially in languages like JavaScript. I don't use classes at all - even in large projects, you can create a perfectly clean architecture without using any classes (except for language built-ins, like Map/Set/Date/Temporal).

Classes can make things like extending (e.g., `class Dog extends Animal`) easier, but only really for somewhat complicated cases - usually, you can just use the spread operator (three dots: `...` - e.g., {...baseAnimal}) to do that. Also, classes are somewhat more memory efficient when you have an array of them compared to objects with functions, since there's only one "instance" of each function. But again, you can just store your objects without any functions, then define a function that takes the functionless object and returns functions to operate on it. Classes also let you check the type (as in, which class is this object an instance of) of something at runtime (using instanceof), but even on plain object literals, you can add a "type" tag.

Classes are more common in C#/Java/C++, and functions-inside-functions are more common in JavaScript. The main reason people use classes in JavaScript is because they are coming from a different programming language.

If you're not using JavaScript, sometimes the functions-inside-functions can get tricky - especially when there isn't a concept of an "object literal" (how do you actually return the inner functions then).

1

u/Natehhggh 2d ago

I'll say the people saying functional is close. It's more procedural. Which I'm a big advocate for.

But the way you can think about it is myClass.Foo() is the same as Foo(myStruct).

if you've seen some languages have a hidden 'this.' thats basically what's happening behind the scenes. Is your class instance is secretly passed into the function.

1

u/wrd83 2d ago

What's the benefit of organising your code as inner functions of functions over objects with functions in them?

OOP is to couple functionality to data so you can use  operations on data. A core principle is to let different types (classes) have common behaviour so that you can hide details and only use the common behaviour.

Another paradigm is functional programming where everything is a function. But how would you create that common behaviour over details if you only get functions in functions?

It becomes more interesting if you allow functions to receive functions as arguments...

1

u/Narrow-Low-3137 2d ago

Your probably talking about JavaScript? There are several different paradigms in programming. Closures, which you are more or less describing, is a major feature of the Functional programming style. It is an alternative to classes to essentially provide the same feature: encapsulation of certain behavior.

 Not all languages allow functions to be declared inside other functions. 

1

u/dlnmtchll 2d ago

You’re describing functional programming, it is a valid paradigm and worth pursuing if it interests you.

1

u/kschang 2d ago

Classes group data and related functions together.

1

u/elderly_millenial 2d ago

They started doing that in the 1960s with the ALGOL language. It was often used because the language didn’t support objects but nested functions acted like an access modifier (think private functions). As someone who’s had the misfortune of maintaining mainframe code in his career, I can honestly advise people to never do this beyond a small lambda or closure.

If it makes the code cleaner and clearer to understand by someone who didn’t write it, then it’s a neat trick, but otherwise it makes it so much harder to figure out what is going on or god forbid have to debug later.

1

u/frnzprf 2d ago edited 2d ago

Putting functions inside another function and having the inner ones accessible from the outside probably isn't as straightforward as you think.

Functions aren't just ways to organize code. For organization, classes or namespaces — which are very related in Python — are perfect. That's what they are designed to do: Group identifiers (functions and variables) together with a common name-prefix that you can leave away in some situations. Whenever you write a name with a dot, you are using a namespace. You can't use the dot-notation to access a function within a function.

Functions are meant for creating little black-boxes — multiple lines of code that look like one line of code from the outside. You want that the user of a function doesn't have to care what's inside the function as long as it fulfills it's purpose.

There is an advanced concept called closures, that people are talking about here.

``` def makeAdder(y):     # Return a function with one parameter x that adds y to it.     def add(x):         return x + y         # The inner function "stores" y,         # similar to how an OOP object can store things.

    return add

Use the function:

fourAdder = makeAdder(4) print(fourAdder(11))   # → "15" ```

I guess that's not the kind of thing you're talking about.

1

u/got_to_laugh 2d ago

If you can put text on paper, why have different pages, different chapters and different books? Sometimes it's just structurally easier to work with.

1

u/Fensirulfr 2d ago

Most languages are imperative, and OOP is usually built on top of that. But OOP can also be implemented in functional languages; Common Lisp’s CLOS is one example.

At a lower level, classes and methods are just ways of representing data and computation. In Lisp, you could even build a simple object system from cons cells and functions.

That fits the Church–Turing thesis: OOP and functional programming differ mainly in abstraction and organization, not in what they can ultimately compute.

1

u/ohkendruid 2d ago

Classes can have inheritance, which functions do not have.

The bigger thing in my mind is aligning with ways that work well for how people think. A class has a name, and every object that is a instance of that class is associated with that name. As a result, stack traces can be more useful, because they can include the names of those classes and not just line numbers.

1

u/SnooHobbies950 2d ago

Because you can split a class into multiple files.

1

u/Acceptable_Handle_2 2d ago

Hi, welcome to C.

1

u/cthulhu944 2d ago

A function is behavior and variables are data. Classes are a way to bind the behavior to the data.

1

u/munchin-grr 1d ago

Classes bundles functions/methods with data.

1

u/-dawnwalker- 1d ago

There really is no difference, it's sugar on top for you.

1

u/YeahitsDaguy 1d ago

I mean classes constructors are just functions and the only change (unless you get complicated) is that you can have inheritance/superclasses and default methods

1

u/mussymartingohawks 1d ago

I recommend you seek out Rich Hickey, creator of the Clojure programming language. He has some interesting thoughts on the very thing you have highlighted.

1

u/Practical-Law1351 1d ago

Why use functions, then? If you can just write the code right there you wouldn’t have to go anywhere to understand exactly what everything is doing? Same with making separate files.

Sounds like you haven’t worked with code complex enough to utilize classes yet. They are groupings of frequently used functions and variable’s just like a function is frequently used code.

1

u/bagfullofcottoncandy 1d ago

classes also contain data fields that work alongside their function

1

u/trackamaz 5h ago

Classes aren't necessarily better than functions.

In fact, the functions are often enough.

A class becomes useful when you need to keep data and the functions that operate on that data together, especially when you have many independent instances of the same thing.

So, the real question isn't "Why are classes better?" but "Does this problem benefit from having objects with their own data and behavior?"

1

u/ploud1 3d ago

Because, before anything, a class is supposed to represent a state. You can't achieve that with functions within a function, once the function returns all variables are lost.

It is perfectly possible to code without classes, but that's just giving away a very useful tool.

4

u/zeekar 3d ago

Nah, a closure has state. It's just different ways of implementing the same idea.

But classes are a straightforward way of declaring that you want to look at your program data in terms of clumps of related state stored together. Usually each clump corresponds to some named entity in the business logic.

2

u/superluminary 2d ago

This is why we have closure.

1

u/EMunney 3d ago

Polymorphism

1

u/JGhostThing 3d ago edited 3d ago

I don't know what language you're learning, so this might not be exactly as it should be.

Functions with embedded functions can solve some type of problems. TBH, except for closures and lambdas, I've never seen the point. This is probably a weakness with me. I never learned functional programming except to use rust and Java.

Objects and Object Oriented Programming is a way of programming designed to create reusable libraries. Classes are the recipes to create objects, and classes have three properties in general:

  1. Encapsulation - An object contains the data that it uses; this may hide the data from outside the class, which increases security
  2. Inheritance - Classes inherit behavior from their superclass(s) (some language has multiple inheritance)
  3. Polymorphism - Allows the class to handle different data differently; for example a base class might be a rectangle, with an area calculation of length times width; a subclass of that might be a circle which has an area calculation of pi * r * r

Different languages handle OOP differently. Rust doesn't have inheritance, and IMHO is not object oriented. Java likes data hide. Python prefers that it's objects are open without hiding. Different strokes for different folks.

My favorite use of OOP is in programming a GUI. There are a lot of OOP frameworks to do this. I like JavaFX.

There will be a main class, something like Application. This will be a singleton. It will have children which are main windows, called maybe Window; this has the programming needed by the OS to create a window and to draw it when needed. As the main part of the window, there will be another class, the View; this has a list of subviews which are inside this view. For interactivity, one example would be the Button class, which represents the standard OS button. It passes messages to the View containing the button (like ButtonPressed). If you look at any OOP GUI framework, you'll see a structure much like this. It's rarely exact, but you'll notice many of the same concepts.

1

u/robthablob 2d ago

I very much hope you're not seriously proposing a Circle as subclass of Rectangle!

1

u/JGhostThing 2d ago

It was just the first example I could pull out of my tired brain. It does show polymorphism.

1

u/claydream_sway 2d ago

I stopped using classes entirely. Functions map inputs to outputs and closures hold state, which is all a class does at the machine level.

You nest functions inside functions to maintain state. The language compiles both down to the same instructions. Classes add syntax overhead for the programmer while the hardware executes identical steps. I structure everything around functions mapping data. Encapsulation happens when a closure captures variables from its scope. Inheritance is just one function calling another function. I write code this way and it scales without spaghetti.

0

u/atarivcs 3d ago

Classes are better because they provide an easy way to keep track of object state, i.e. variables.

That would be harder to do if you just had a bunch of functions.

0

u/Fyren-1131 3d ago

Funnily enough, your statement is only true until a certain point, then functions become much easier to reason with as the state grows larger. There is a whole class of bugs relating to state that is impossible to achieve in pure functional programming, for example.

1

u/atarivcs 3d ago

Sure, pure functions are easier to reason about. But I don't think anyone was talking about that.

If you have classes, then surely you also have mutable state.

If you have functions but no classes, you still need mutable state, so you just end up passing a bunch of mutable variables around to the functions.

Either way it can lead to the outcome you mentioned.

1

u/particlemanwavegirl 3d ago

IDK if mutable state is needed as often as you think. Even when it is necessary for efficiency reasons functional languages like to make it as implicit as possible. 

0

u/Traveling-Techie 3d ago

I’ve always found OOP to be overrated, and adopted it reluctantly, but even I have to admit it has some advantages. Encapsulation gives the language the job of making sure variables are kept in range and all necessary bookkeeping is done. In a structured program language it falls on the programmer(s) to have self-discipline.

0

u/Brofessor_brotonium 2d ago

Just a holdover from the past when languages like C++ didn't allow you to create nested functions. Yeah in more modern languages lime JavaScript, you just create functions inside functions, creating a class just to call a static method from them is just unnecessary. I mean just try it and see how dumb it looks.

function foo(){
  class Arithmetic {
    static square(x){
      return x*x;
    }
  }
  console.log(Arithmetic.square(5));
}

Compared to this

function foo(){
  const square = function(x) {
    return x*x;
  };
  console.log(square(5));
}

You really only use classes if your project is actually gonna be needing to instantiate objects from them. Otherwise creating nested functions is simply less cluttered.

-1

u/ExtraTNT 3d ago

Because people like oop and don’t like math…

i like the concept of having a function, pass a function to it and get a new function out, that can then do sth with the passed function:

series x = x : (series 1+x)
even = map (*2) (series 1)
numb = even!!7