DEV Community

loading...
Cover image for How do you convert a class to functions in FP?

How do you convert a class to functions in FP?

Michael
I'm a self-taught dev focused on websites and Python development. My friends call me the "Data Genie". When I get bored, I find tech to read about, write about and build things with.
Updated on ・3 min read

Intro

Hey all.

I've done a lot of reading lately on Object Oriented Programming (OOP) and Functional Programming (FP). I have a question to ask and have some ideas to share to get the conversation going.

I know the benefits and typical code for each approach. I do want to move to more FP, to make my code more modular and to be easier to test and debug. I need advice on how.

Question

The question I have for you, is how do I take code that I have as a class with methods and rewrite it as functions? For current projects and for any new projects where I am tempted to use OOP but choose to use FP.

How do I setup my code with all functions and no classes - just so it looks good technically but is a way that feels natural/smooth and DRY, including when applied to large projects.

In one of my projects, I have a class which takes some variables on initialization and then some methods which use those initial values on the object and sometimes more arguments and then return something.

My ideas

Here is how I might do calls in OOP to setup an instance and then call a method which adds a given amount to values in the class.

foo = 1
bar = 2

myObj = new MyClass(foo, bar)
myObj.add(100)

myObj.foo
// 101
Enter fullscreen mode Exit fullscreen mode

Many function arguments

Should I take the arguments out of the init/constructor method and rather make them the first arguments of each function? An argument I've seen against this is that the code becomes verbose - especially if you want to pass an argument down several calls and then the top-level function has to take everything.

foo = 1
bar = 2

add(foo, bar, 100)
// Returns [1, 2]
Enter fullscreen mode Exit fullscreen mode

Pass key-value pair

I had another idea where the first argument of the function in the FP approach is an object like a dictionary / hash / associative array. So instead of passing the same bunch of arguments to each function, you create an object with those values on it an then pass the as a single parameter to the function.

e.g.

x = {foo: 1, bar: 2}

add(x, 100)
// Returns {foo: 101, bar: 102}
Enter fullscreen mode Exit fullscreen mode

Use a type

In TypeScript, you can even use an interface so it doesn't matter whether the object coming in is an associative array or a class instance, as long as it has the expected key-value pairs then the compiler will run. I've read about something similar I think for types or structs in other languages Haskell, where you guarantee at compile time that the object you pass in will have the necessary keys.

e.g.

interface myType = {
  foo: Integer,
  bar; Integer
}
Enter fullscreen mode Exit fullscreen mode

Then the function add would only accept argument x if it matches the structure of interface myType. Or maybe it is a type rather.

Bad ideas

I thought of some approaches to avoid.

Using global variables magically called in functions.

Or using functions define inside functions (common in JavaScript, maybe because the class keyword came to JS very late). I hate this style because you can't use the inner function without the outer one called first, so it is like a class and methods but more chaotic for state and unit tests.

Conclusion

Please let me know your thoughts. By the way my background is Python and JavaScript.

Thanks.

Credits

Cover image by @hishahadat on Unsplash.

Discussion (4)

Collapse
vonheikemen profile image
Heiker

Classes are not the problem. I would focus on the methods, do they behave like pure functions? Refactor those that don't.

For new projects you might want to start making a dedicated space where you have all your pure functions. The idea here is that you have a place where everything is pure and nice, and another where you can bend the rules a little bit.

Collapse
michaelcurrin profile image
Michael Author

Thanks, good point. Refactoring the methods that do too much and are hard to test will help achieve some of my FP goal while still using classes.

My concern is that I will fall into OOP thinking and pitfalls by using classes, so am hoping to change the mindset for new projects.

One of the bad things I've about OOP is developers tend to put way too many methods on a class it makes sense conceptually to put the methods for updating employee and representing employee in the same class. But these are separate responsibilities and so should be in different modules and also should not depend on each other and should rather be dumb - just processing data they get.

I like the idea of pure functions in one section and less pure in another. Like where the IO gets handled.

Collapse
michaelcurrin profile image
Michael Author

Thanks for your input.

Yes I had thought about currying as well - Python has the partial function which helps with this. I realize that currying with two functions is like calling the constructor and then a method, so it sounds like the FP way of handling the initial values