How is a functional programming-based JavaScript app laid out?
Asked Answered
L

4

32

I've been working with node.js for a while on a chat app (I know, very original, but I figured it'd be a good learning project). Underscore.js provides a lot of functional programming concepts which look interesting, so I'd like to understand how a functional program in JavaScript would be setup.

From my understanding of functional programming (which may be wrong), the whole idea is to avoid side effects, which are basically having a function which updates another variable outside of the function so something like

var external;
function foo() {
   external = 'bar';
}
foo();

would be creating a side effect, correct? So as a general rule, you want to avoid disturbing variables in the global scope.

Ok, so how does that work when you're dealing with objects and what not? For example, a lot of times, I'll have a constructor and an init method that initializes the object, like so:

var Foo = function(initVars) {
   this.init(initVars);
}

Foo.prototype.init = function(initVars) {
   this.bar1 = initVars['bar1'];
   this.bar2 = initVars['bar2'];
   //....
}

var myFoo = new Foo({'bar1': '1', 'bar2': '2'});

So my init method is intentionally causing side effects, but what would be a functional way to handle the same sort of situation?

Also, if anyone could point me to either a Python or JavaScript source code of a program that tries to be as functional as possible, that would also be much appreciated. I feel like I'm close to "getting it", but I'm just not quite there. Mainly I'm interested in how functional programming works with traditional OOP classes concept (or does away with it for something different if that's the case).

Locksmith answered 20/4, 2010 at 18:9 Comment(1)
I just wanted to point out that I now realize that a Foo.init method doesn't really make sense if you're trying to adhere to functional programming, because the only reason I would have for an init method would be if I wanted to re-initialize a Foo object later...which is totally against the idea of immutability. So instead of that, I should just do whatever I need to do to initialize the object in the constructor, then next time I need to either update the Foo object or re-initialize it, I just make a brand new instance of Foo and deal with it. It's all starting to make sense!Locksmith
H
32

You should read this question:

Javascript as a functional language

There are lots of useful links, including:

Now, for my opinion. A lot of people misunderstand JavaScript, possibly because its syntax looks like most other programming languages (where Lisp/Haskell/OCaml look completely different). JavaScript is not object-oriented, it is actually a prototype-based language. It doesn't have classes or classical inheritance so shouldn't really be compared to Java or C++.

JavaScript can be better compared to a Lisp; it has closures and first-class functions. Using them you can create other functional programming techniques, such as partial application (currying).

Let's take an example (using sys.puts from node.js):

var external;
function foo() {
    external = Math.random() * 1000;
}
foo();

sys.puts(external);

To get rid of global side effects, we can wrap it in a closure:

(function() {
    var external;
    function foo() {
        external = Math.random() * 1000;
    }
    foo();

    sys.puts(external);
})();

Notice that we can't actually do anything with external or foo outside of the scope. They're completely wrapped up in their own closure, untouchable.

Now, to get rid of the external side-effect:

(function() {
    function foo() {
        return Math.random() * 1000;
    }

    sys.puts(foo());
})();

In the end, the example is not purely-functional because it can't be. Using a random number reads from the global state (to get a seed) and printing to the console is a side-effect.

I also want to point out that mixing functional programming with objects is perfectly fine. Take this for example:

var Square = function(x, y, w, h) {
   this.x = x;
   this.y = y;
   this.w = w;
   this.h = h;
};

function getArea(square) {
    return square.w * square.h;
}

function sum(values) {
    var total = 0;

    values.forEach(function(value) {
        total += value;
    });

    return total;
}

sys.puts(sum([new Square(0, 0, 10, 10), new Square(5, 2, 30, 50), new Square(100, 40, 20, 19)].map(function(square) {
    return getArea(square);
})));

As you can see, using objects in a functional language can be just fine. Some Lisps even have things called property lists which can be thought of as objects.

The real trick to using objects in a functional style is to make sure that you don't rely on their side effects but instead treat them as immutable. An easy way is whenever you want to change a property, just create a new object with the new details and pass that one along, instead (this is the approach often used in Clojure and Haskell).

I strongly believe that functional aspects can be very useful in JavaScript but ultimately, you should use whatever makes the code more readable and what works for you.

Heroic answered 23/4, 2010 at 1:17 Comment(4)
thanks for your reply and the helpful links. I really like the idea of just passing new objects to my functions and having them act on it. That was an aha! moment for me. The one thing I was still struggling with fp in general, is keeping functionality together code wise. With OO, it's easy because most everything is a method off of the class (ie car.startEngine(); car.applyBrakes();). With FP, I think I can do a similar thing by using a namespace though and just having my methods require an object as the first argument. so var car = {}; car.startEngine = function(carObj) {}Locksmith
@user321521, why not to put the function into the prototype of the object you pass to it? Separating data from operations does not make the code more or less FP. It's quite orthogonal.Hilariohilarious
@Brian What you call an object in the above example is not so much an object as it is a struct or a tuple, by which I mean it is purely a data type. Objects (as in Object Oriented) are encapsulations of data and methods and they are characterized by the fact that they can change state what you call methods on them. Now, whatever you choose to call that, it's a concept that permeates JavaScript and one that you'll have to do without if you choose to pursue a purely functional style.Culbreth
Sum should be function sum(values) { return values.reduce(function(a, b) { return a + b; }); }Triatomic
C
5

You have to understand that functional programming and object oriented programming are somewhat antithetical to each other. It's not possible to both be purely functional and purely object oriented.

Functional programming is all about stateless computations. Object oriented programming is all about state transitions. (Paraphasing this. Hopefully not too badly)

JavaScript is more object oriented than it is functional. Which means that if you want to program in a purely functional style, you have to forego large parts of the language. Specifically all the object orient parts.

If you are willing to be more pragmatic about it, there are some inspirations from the purely functional world that you could use.

I try to adhere to the following rules:

Functions that perform computations should not alter state. And functions that alter state should not perform computations. Also, functions that alter state should alter as little state as possible. The goal is to have lots of little functions that only do one thing. Then, if you need to do anything big, you compose a bunch of little functions to do what you need.

There are a number of benefits to be gained from following these rules:

  1. Ease of reuse. The longer and more complex a function is, the more specialized it also is, and therefore the less likely it is that it can be reused. The reverse implication is that shorter functions tend to more generic and therefore easier to reuse.

  2. Reliability of code. It is easier to reason about correctness of the code if it is less complex.

  3. It is easier to test functions when they do only one thing. That way there are fewer special cases to test.

Update:

Incorporated suggestion from comment.

Update 2:

Added some useful links.

Culbreth answered 22/4, 2010 at 10:2 Comment(13)
I disagree. JavaScript is actually more functional than object-oriented. It has closures, first-class functions, it lacks classes and inheritance. Syntactically, it's more like Java than Lisp but overall actually shares more in common with the latter.Heroic
You're wrong: JavaScript has both classes and inheritance (but maybe not in the style you're used to). And most if its datastructures are mutable which puts it apart from all purely functional language. I disagree strongly with the notion that it is more like Lisp than it is like Java.Culbreth
Adam, I very agree with the rules you stated. it also would be valuable to add rationale (or link to) why the rules are really valuable. IMHO: 1. easy to reuse the code 2. reliability of code (easy to reason about correctness of the code) 3. easy to test the codeHilariohilarious
I think JavaScript better suites for OOP paradigm then FP.Hilariohilarious
@KaptajnKold, sure, you can use some of JavaScript's features in place of classes and classical inheritance but that doesn't meant JavaScript has classes and classical inheritance (you're just using prototypes). You can even tack on some encapsulation but still, you're just using prototypes to create object-oriented concepts. It works for a lot of people and that's fine (probably because it works well). In the end, you'll find that JavaScript is prototype-based and not fundamentally object-oriented at all.Heroic
@KaptajnKold, sorry, I also wanted to point out that most data structures in Lisp are mutable, that doesn't make it object-oriented.Heroic
@Brian Why do you not think prototype based inheritance constitutes "real" object orientation? Do you also thing that Go is not object oriented because it doesn't have inheritance at all? I would argue that it's the encapsulation of functions and state that makes a language object oriented. Re. Lisp: I stand corrected. Still, most languages considered to be purely functional do not have mutable data structures.Culbreth
@Culbreth I can see your point. No, I would not call Go object-oriented. I think you're describing class-oriented, not object-oriented features (class-orientation is just one important part). Using JavaScript's prototypes it's possible to create inheritance, abstractions, polymorphism, encapsulation, etc. which are object-oriented features. In JavaScript these are all just emulations of classical object-oriented languages. By itself, JavaScript is not an object-oriented language but it can be made to work like one. If it works like one, doesn't that make it one? Good point.Heroic
@Brian I still think you misunderstand what exactly makes a language object oriented, but I guess we're not going to agree on this. I just wanted to point out that the creators of Go themselves call it "a profoundly object oriented language. Arguably more so than Java" (citing from memory from the tech talk on golang.org). I know, appeal to authority is a weak form of argument, but I give a lot of credit to the opinions of these guys.Culbreth
@Culbreth I also respect the Plan9 guys that have created Go. I think they're referring to the fact that Go acts very similar to Smalltalk in regards to objects. Smalltalk is regarded as the creator of object-orientation but the term has since changed significantly. I think JavaScript would quite possibly be considered object-oriented by the original definition.Heroic
@Brian According to you, what is the "original definition" of object orientated programming? And what is the current one? I looked at the articles for "Object Oriented Programming", "Functional Programming" and "Prototype-based programming" on Wikipedia, and they all seem to align with my point of view.Culbreth
I think we need to distinguish between "purely functional" and merely "functional." If we require purity to be considered functional, that throws out the whole ML family, the whole Lisp family, Erlang — pretty much everything but Haskell and a few esoteric languages.Financial
@Culbreth SmallTalk's object orientation is what I consider to be an original version: en.wikipedia.org/wiki/SmallTalk#Object-oriented_programmingHeroic
H
2

I think, http://documentcloud.github.com/underscore/ should be nice fit for what you need - it provides the most important higher-order functions for functional programming and does not has client-side functions for DOM manipulation which you don't need for server side. Though I don't have experience with it.

As a side note: IMHO primary feature of functional programming is Referential transparency of a function - function result depends only on its parameters - function does not depend on changes on other objects and does not introduce any change except its result value. It makes it easy to reason about program's correctness and very valuable for implementing of predictable multi-threading (if relevant). Though JavaScript is not the bet language for FP - I expect immutable data structures to be very expensive performance-wise to use.

Hilariohilarious answered 21/4, 2010 at 21:44 Comment(1)
Yes, I'm using underscore.js currently and I've used it to eliminate all of my for loops so far. That's kind of the key to FP as I see it as well. The idea of just passing new objects to functions as mentioned by brian below really opened up a block I was having on how to deal with it. I'll see how it performs. Node.js / V8 seems really fast from everything I've read so far, so it'll be interesting to see if this technique works as well.Locksmith
V
0

So 2 things to point out ,

  1. In your first example your variable would not be leaking into the global area and is the way it should be done , try to never use variables without declaring them i.e. test = 'data' would cause data to leak into the global area.

  2. Your second example is correct as well , bar1 and bar2 would only be declared on the Foo object.

Things to keep in mind try not to overuse prototyping since it applies to every object that you create , this could be extremely memory intensive depending on how complex your objects are.

If you are looking for a app development framework , have a look at ExtJs. Personally I think it would fit perfectly into the model you are trying to develop against. Just keep in mind how their licensing model works before getting heavily invested in it.

Vaticide answered 20/4, 2010 at 19:12 Comment(1)
thanks for the comment. node.js is server-side javascript, so I don't think extJS is meant to work there, but I may be mistaken. I'm more interested in just best practices for applying the functional programming model to javascript in general. I know how to build the app if I just use traditional object oriented design (good point on over prototyping though), but I want to know how to attack it using the concepts of functional programming as much as I can.Locksmith

© 2022 - 2024 — McMap. All rights reserved.