
Classes are a way of writing higher order functions - stopachka
https://stopa.io/post/250
======
kazinator
> _Yup, really. Classes are just higher order functions, which accept
> arguments (constructor) and return a list of functions that can manipulate
> those arguments (methods)._

Nope, really they are not. Rather, objects are _run-time_ , _publicly
accessible_ environments (bindings of names to slots).

Since functions also have environments, we can come up with some contrived use
cases whereby a rigorously encapsulated OOP example revolving around a class
that is sealed against extension and uses no inheritance or other OOP
mechanisms is nicely mimiced by a vector of functions that share the same
environment.

But imitating some facets of a thing is not being that thing. A dog standing
on hind legs isn't a man.

A more fully featured OOP can be built up, which yet keeps using lexical
variables for slots. Public access to slots by name can be implemented by
having a standard function supported at the same position in the function
table, which takes a symbol argument, and switches on it to map it to a
variable in its environment.

Providing possible implementation mechanisms for thing is also not being that
thing.

We can easily reverse this, too, and claim that functions are just objects.
Compilers for lexical closures do things like flatten the environment into an
array in which items are accessed by position. So, first class functions are,
under the hood, nothing but code, plus an array, in machine language. And
since data structures are also some code offsetting into arrays, it's all the
same.

You know, the moment I saw a NAND gate schematic, my mind opened to an amazing
revelation: we don't need both zeros and ones, just zeros and NAND gates! The
number one is nothing but a zero, duplicated into the two inputs of a NAND
gate.

~~~
ookdatnog
> You know, the moment I saw a NAND gate schematic, my mind opened to an
> amazing revelation: we don't need both zeros and ones, just zeros and NAND
> gates! The number one is nothing but a zero, duplicated into the two inputs
> of a NAND gate.

This is not as absurd as you think it is. The most commonly used definition of
the natural numbers
([https://en.wikipedia.org/wiki/Peano_axioms#Formulation](https://en.wikipedia.org/wiki/Peano_axioms#Formulation))
is structured in a way similar to your description: we have a single
explicitly declared natural number (zero), and all other natural numbers are
defined as a sequence of function applications on zero (ie 4 is defined as
S(S(S(S(zero))))).

Our notation for numbers is just "syntactic sugar" on top of this
representation: useful when doing practical work with numbers, but only a
hindrance when you're studying the concept of "number" itself.

Analogously, in programming language theory (studying the properties of
programming languages moreso than trying to do program things in them), we
often prove properties of languages by studying extremely frugal, tiny
languages (often called "calculi"), that only have the absolute minimum
primitive constructs.

Realizing that a construct can be expressed as "syntactic sugar" on top of a
simpler one (objects on top of closures, for instance), is useful in this
setting because it reduces the number of cases in proofs.

~~~
ithinkso
This touches on an interesting topic I've been thinking about for quite some
time now. I have a somewhat reverse feeling about the definition of natural
numbers (or for that matter, about the 'foundation of mathematics' as in ZFC
set theory or whatever you want to choose) than you've presented above.

Those definitions were developed after we had something useful in order to
'codify' it and make it more precise. They are not, in my opinion, a basic
blocks that the rest is built from but an added layer of abstraction _on top
of_ whathever it is you're defining.

I don't mean I don't understand set theory and the role it has, or advocating
for any other system, I absolutely love it.

What I mean is, in practical things (programming languages etc.), it feels a
bit counter-productive to me to reduce them to the simplest possible
definitions/terms (that have to fit to the particular use case by definition),
declaring that a building block and then explaining every other concept in
those terms as if it was a proof that we have trully found a foundation and
the rest is just a 'syntactic sugar'

edit: You all probably know this famous gif of a ballerina that can rotate to
the left or to the right depending on how you think about it. After writing
the above post the notion of S(S(S(S(0)))) keeps flipping in my brain between
being an abstraction of and simplification of natural numbers. It's weird.

~~~
ookdatnog
I agree with what you're saying, actually. I think these questions require
drilling down to philosophical questions such as "what are numbers", "what is
the essence of 'number'", "are numbers even real", etc. So I'll give it a go
and be shamelessly long-winded about it :)

I think that numbers, set theory, programming languages, etc, are all
abstractions. Forming abstractions is a mental tool associated with our
ability for language: we spot a pattern and we give that pattern a name. Once
we've given it a name, we can talk _about_ the abstract concept as a subject
of our statements.

Perhaps the simplest form of abstraction we're capable of is "categorization".
Ie we see a pointy-eared small animal that makes meowing sounds, we another
one, and another one, ... and even though none of them are identical, our
brain picks up on certain patterns in these creatures. We know that when we
next see one of them, we can expect certain behaviors. So we give it a name,
let's say, "cat", and now we can talk about the abstract concept of "cat"
without referring to any specific individual cat. To see how big a deal this
is, I find it useful to remember that cats aren't explicitly defined in the
fabric of the universe, like they would be in a computer program (where we'd
have a "Cat" data structure or object, usually), they're just emergent
behavior of interacting molecules.

But we can do more, we can also abstract out properties of objects. We can see
that some frogs have a similar color to the leaves of most trees, so we can
give this leaf-color a name, "green", and talk about the abstract concept of
"green" without referring to a specific green thing. You can just say "I like
green" (no one will ask you "a green what?"), or "mixing green and blue makes
cyan" (no one will ask "mixing green and blue what makes cyan what?").

And then we also have "chunking", where we can talk about sets of objects as
objects themselves. So we can talk about "a herd of sheep" as a singular
thing. Our ability to abstract out properties of objects also applies to these
chunked concepts. One property of a set of objects is "quantity". Speculation
ahead. Initially we probably only had fairly vague terms to talk about
quantity, perhaps individual words for small quantities (one, two and three,
maybe), and after that it's just "many". But it seems we figured out pretty
fast that counting sheep, counting apples, or counting pebbles are really in
some sense "the same thing", so we might have first learned to count through
some unary "notation" even though we had no names for quantities. We'd make
carvings into bone or carry a bag of pebbles, one carving or one pebble for
each sheep in our herd. Then we notice that certain operations on these
quantities are also all "the same": it doesn't matter whether you're adding
pebbles, sheep, carvings, ... you're always doing the same thing. So after a
while we start using these operations to define bigger numbers (the French
still call the number 80 "quatre-vingts" or "four twenties"). Now all numbers
become nameable, and eventually we streamline and standardize these names.

So now we have a name for every number, and we can talk about "thirty-two"
without getting back a confused reply "thirty-two what?". And we can talk
about operations on these numbers, like addition, multiplication, etc, but our
hunger for abstraction isn't satiated at all. Since now we can talk about
operations, we can also talk about properties of operations, so we notice that
you can flip the arguments of additions and multiplications, and we give that
property a name, commutativity, and we go on to invent abstract algebra.

After doing maths for a few thousand years we start looking into patterns into
the different, disparate branches of maths at the time (geometry, number
theory, logic, etc), and notice that the common pattern is that all of them
are doing deductive reasoning, and that should be modellable by logic. So we
abstract out the common bits and come up with set theory and proof theory and
the like. And in that process we notice that number theory has unnecessarily
many axioms and Peano figures out we can just use induction to define the set
of natural numbers.

So yes, our intuition for numbers precedes Peano's definition by millennia or
far more than millennia. But I'd say that's how it goes for _every_
definition. We always start by noticing some pattern, which initially we can't
quite put our finger on (for example, Leibniz had a vague intuition that a lot
of work in mathematics was in some sense so mechanical that one should be able
to have a machine do it; he couldn't quite define computation yet but his
hunch was spot-on), and then we try to refine our thoughts and come up with a
definition.

In that sense, I don't think it's more meaningful to worry about the "true
nature" of a number (the Peano definition, or some other notation?) than it is
to worry about the "true nature" of the color red (is it its wavelength on the
electromagnetic spectrum? but a wavelength can be expressed as a number; so is
the essence of red just a number? or its RGB value, which is linked to how
humans perceive color?). Both numbers and colors are abstractions, and
abstractions are mental tools. They are a means to an end: to make sense of
the world and communicate about it to other humans. And we use just use the
tool that is most helpful given the problem at hand. For most practical
applications we're going to use a notation that's compact and easily
manipulated (Arabic numerals), but when we're studying the foundations of
mathematics, it's more sensible to reduce everything to its smallest, most
elegant definition possible. Neither view is "more true" than the other, in
both cases you're doing no more than naming patterns in herds of sheep and
piles of apples.

~~~
stopachka
This is a fantastic explanation ookdatnog. Thank you -- if you have a blog
would post this up! More people should see this :)

------
goto11
Objects are just a poor mans closure.

Closures are just a poor mans object.

(Not sure where this quote is from originally? Maybe here:
[http://people.csail.mit.edu/gregs/ll1-discuss-archive-
html/m...](http://people.csail.mit.edu/gregs/ll1-discuss-archive-
html/msg03277.html))

~~~
Someone
There also is the classical example of defining _cons_ , _car_ , and _cdr_ as
closures in SICP:

    
    
      (define (cons x y)
        (lambda (m) (m x y)))
    
      (define (car z)
        (z (lambda (p q) p)))
    
      (define (cdr z)
        (z (lambda (p q) q)))
    

Here, _cons_ , instead of returning an object with two values, returns a
closure that captures the two values. _car_ and _cdr_ call that closure,
passing it another closure. The _cons_ closure calls that closure, passing the
the two values.

Explanation at [https://stackoverflow.com/questions/21769348/use-of-
lambda-f...](https://stackoverflow.com/questions/21769348/use-of-lambda-for-
cons-car-cdr-definition-in-sicp).

~~~
chriswarbo
[https://en.wikipedia.org/wiki/Church_encoding](https://en.wikipedia.org/wiki/Church_encoding)

~~~
Joker_vD
Also,
[https://en.wikipedia.org/wiki/Scott_encoding](https://en.wikipedia.org/wiki/Scott_encoding)

Of course, it completely kills (or "stress-tests", if you will) the branch
predictor in your CPU.

------
ledauphin
This both is and isn't true, and the finer points revolve around
mutability/concurrency and implementation inheritance.

Modern computers are inherently concurrent and mutable, and these fundamental
realities have been shown over and over again to cause hard-to-understand
issues in sufficiently complex codebases. In the vast majority of OOP
languages, instantiated classes are mutable-by-default and can be mutated by
multiple concurrent operators (threads, coroutines, etc). This makes them
actually quite similar to the underlying computing model - even though they're
a high-level abstraction, they force you to deal with the knowledge that the
memory at any address can be modified at any time with no warning. [1]

Classes in most languages also offer implementation inheritance, which boils
down to an approach to "rebundling" the constituent functions in ways that are
arguably simple enough, but generally in practice it has been found to be hard
for programmers to reason about. Dynamic dispatch is very powerful, and the
way that most inheritance mechanisms expose this seems to be a model that
programmers understand in theory but fail to consistently remember in
practice.

In my opinion, the fundamental difficulty with classes is that in most
languages, you get all of these tools bundled (complected) into the same
toolbox without any say in the matter. If you didn't want inheritance, too
bad. If you didn't want concurrent mutability, you're now being asked to
design a complex state machine to prevent it, rather than it being excluded
off the bat by most functional approaches. Functional approaches force you to
opt in to most of the footguns that are included "out of the box" in OOP.

Classes will remain the best approach in many OOP languages for RAII-shaped
problems, where some part of an application needs to encapsulate and manage a
limited, shared, and potentially mutable resource (such as a file handle, a
database connection, or an in-memory cache), because classes are an
abstraction that maps cleanly to shared mutable state with locking mechanisms.

[1] You can of course also shoot yourself in the foot with closures that
themselves contain mutable state (e.g. some kind of mutable container), and I
think this is a rarely-considered danger for functional paradigms in languages
that default to mutable data structures.

~~~
SolarNet
I'm not sure you are really disagreeing. Which is to say I don't see where the
not "isn't true" part come from.

Yes classes are closer to the physical reality of modern computer (and that is
one reason I prefer C++), but they are still the same construct as a closure
and vice-versa. Everything is just implementation details.

Again I grant that languages designed around classes (or really in my opinion,
around the physical reality of the device implementing them) are more useful
_in practice_. But from a conceptional abstraction point the post is true.

~~~
chowells
It's not true in the sense that classes are higher order functions + a lot of
junk that the GP examined in some detail. All that junk adds a lot of
complexity and makes classes significantly harder to work with.

------
knubie
OOP is an abstraction over functions, but it can be explained much more simply
without closures. Classes introduce a convenient syntax / abstraction over
polymorphism, and can be written with plain functions without the need for
closures. Methods are just polymorphic functions that accept an implicit
"self" argument, which is used to dispatch.

Taking the example from the article:

    
    
      function Person(firstName, lastName) {
        {
          type: "Person",
          fName: firstName,
          lName: lastName
        }
      }
    
      function getFullName(this) {
        switch(this.type) {
          case "Person":
            return this.fName + ' ' + this.lName;
          default:
            throw("TypeError getFullName is undefined for " + this.type ".")
        }
      }
    
      function setFirstName(this, firstName) {
        switch(this.type) {
          case "Person":
            this.fName = firstName;
            break;
          default:
            throw("TypeError setFirstName is undefined for " + this.type ".")
        }
      }
    

From here whenever a "method" is called, the program inspects the "type"
attribute (this process is abstracted and hidden in OOP languages), and uses
that to invoke the correct implementation of the method.

    
    
      let person = Person("John", "Foo");
      getFullName(person);

------
munchbunny
It's a cool idea, and I'm sure everyone gets a pleasant jolt when they make
the connection (I sure did), but you probably already understood this idea at
some subconscious or conscious level in order to get anything nontrivial done
with a functional language.

It's one of the first things you're taught if you are learning a functional-
at-its-roots language. Not JavaScript, which is mixed-paradigm at its roots.
For me it was Scheme in college.

If you're learning a functional language, combining closures and functions
that return functions to carry around "instance fields" and "instance methods"
is what you learn right after you've gotten over the basics like map/filter
and tail recursion. The equivalence of this pattern to classes is something
you'll understand intuitively, even if you haven't put words to it yet.

~~~
commandlinefan
> Not JavaScript

Funny enough, I actually had the referenced epiphany while learning
JavaScript, since this idiom is so common in it.

~~~
munchbunny
Is it actually that common? Using a higher order function that returns member
fields/methods which you then actually call?

Higher order functions are common in JavaScript, and closures are as well, but
I don't recall seeing them used as substitutes for classes or vice versa for
years at this point. With JavaScript you don't have to use closures and higher
order functions to do modularization because you have classes, and you don't
have to use the functor pattern (like Java before Java 8) because you have
higher order functions.

ES5's syntax for object types looked a lot more like "closures with syntax
sugar" than ES6 and later JavaScript syntax with explicit class declarations.

~~~
Weebs
It's probably not common, but for me the answer lies here:

> I don't recall seeing them used as substitutes for classes or vice versa for
> years at this point

I had a fairly large school project developing a JavaScript application back
before ES6, and kept searching for a better way to structure my code because I
found it awkward using prototypes + binding this for events. Eventually I
found a hidden golden nugget of a tutorial that showed me how to do it with
closures and I was in awe that it somehow wasn't the norm (and obviously how
cool it was to build objects out of functions!)

------
didibus
You shouldn't analyse programming constructs based on their implementation in
my opinion. Go down deep enough in the rabbit whole, and you'll see everything
is just a Turing machine.

A more useful analysis in my opinion is to focus on the developer ergonomics
of the language. That includes how the construct is used or can be used, any
properties it exhibits or guarantees, what it prevents you from doing, etc.

From that lens, the ergonomics of a Class and a Function Closure are not at
all the same.

------
erikerikson
Review:

Consider replacing:

    
    
      return function(method) { 
        switch (method) { 
          case 'getFullName': 
            return getFullName;
          case 'setFirstName': 
            return setFirstName;  
        }
      }
    

With:

    
    
      return { 
        getFullName,
        setFirstName,
      }
    

And leaving client code unchanged.

This leaves callers with a struct but is cleaner and more direct. So far as I
can tell, modules and closure usage are objects in JavaScript.

I'm curious if you might have insight into what this approach might block
other than exclusively using functions?

~~~
stopachka
Hey erikerikson -- I think your solution is indeed equivalent, and I would say
even more idiomatic js.

The reason I chose the first option, was to really bring home the point that
all of this could be expressed with closures.

------
drchopchop
A class, generally speaking, is a binding of functions and data.

In the functional example, where does Person store the fName and lName
variables? Is there an intrinsic/hidden 'this' pointer? If functions persist
data, are they really classified as functions anymore?

The message passing part isn't very relevant, as the concept of calling a
function pointer via string lookup is present in many dynamic languages (Ruby,
etc).

~~~
crdrost
No this is a really important question, and it has an answer.

They are called closures. They are "environments" in which variables live,
each of which can have a parent environment dictated by whatever rules there
are. (Some programming languages have it where every use of curly braces
creates a sub-environment; in JavaScript originally only the function keyword
would introduce a sub-environment and if you write `if (something) { var x =
123; }` then `x` belongs to the parent closure and it might contain
`undefined` if the branch was not triggered. Since then JS has introduced
let/const which are scoped to curly brackets.)

When you declare a function it still has access to the full space of variables
which it was lexically defined with. If you mutate those with one function
then another function which has access to that environment can see those
changes, etc.

~~~
drchopchop
Good point, I guess what I was trying to get at is that an object is more
equivalent to a closure (function + data i.e. local stack environment) than
just a function (which executes with input parameters). The top-voted response
put that more eloquently than I did.

------
choeger
Actually, the more precise formulation would be: classes are related to
functions as both are abstractions.

The author conveniently leaves out the differences: classes yield objects,
whereas functions yield any kind of value. Classes are second-class citizens,
whereas functions (usually) are first-class. Functions _have_ a type, whereas
classes (often) _are_ (or are isomorphic to) one.

------
bitL
Higher order functions are just a fancy way of writing classes.

------
CodeArtisan
You can implement an object-- a data abstraction technique where the said data
(the attributes) is hidden behind a set of operations (the interface)-- with
classes or high order functions or prototypes but that doesn't mean those are
equivalent, especially software engineering wise.

------
saagarjha
Well, somewhat. Passing messages is inherently more dynamic, as you can see:
you can change the string to anything at runtime, even something that doesn't
exist, you can intercept the message and send it somewhere else or handle it
however you wish. Static dispatch doesn't let you do this, but you generally
get the advantage of faster calls and better compile-time diagnostics. In
simple cases, the programming style can be similar, but for more advanced
features they really differ in the kinds of things they support.

------
ed25519FUUU
Maybe I'm confused by this particular example, but what languages would allow
functions to store the value of the constructor like that without closures?
The thing I don't like about closures is that they can get messed up easily,
and not even all OO languages support them.

I often think of functions as intentionally "stateless", NOT persisting any
value. For that a class is used, if anything for safety.

~~~
Izkata
> Maybe I'm confused by this particular example, but what languages would
> allow functions to store the value of the constructor like that without
> closures?

It's javascript, where all functions are closures.

------
flowerlad
I don't get why so many JavaScript developers thing functional is cool.
Functional has been around for 30+ years. OOP won against functional because
OOP is easier to understand and leads to more maintainable code. These days
people are taking a second look at functional because functional avoids state,
which makes it easier to write concurrent code with no locks. (This has
suddenly become important because Moore's law is coming to an end, and CPUs
are adding more cores instead of making cores faster and faster.) But this
advantage of functional is not applicable to JavaScript because there are no
locks in JavaScript in any case!

Functional programming actually brings some benefits to backend code. To take
advantage of the extra cores in a CPU you add threads, but if these threads
are continually needing to lock in order to serialize access to shared state
then concurrency is diminished. The more cores you have, the more threads you
have, and then the more you have to lock. Functional style solves this problem
by not having mutable state.

But when it comes to JavaScript these benefits don't exist. That's not to say
there are no benefits at all to incorporating some functional style into
JavaScript code, but wholesale replacement of OOP with functional style is not
warranted.

~~~
lukevp
Functional programming is getting popular in JavaScript not because of
serializability of state changes across threads, but because immutable state
and immediate-mode GUIs go hand in hand. React, as an example, works as an
immediate-mode GUI (re-rendering VDOM on every state change) on top of a
retained-mode GUI (the DOM). You manipulate your state using reducer functions
and the library works behind the scenes to convert that to a UI. It alleviates
all of the weirdness and performance issues of interacting with the DOM when
state changes.

GUI programming is traditionally retained-mode. OOP is traditionally state
encapsulation and mutability. OOP and retained-mode GUIs are conceptually
similar, and Functional Programming and immediate-mode GUIs are conceptually
similar.

Here's a good explanation of this: [https://medium.com/@puppybits/immediate-
mode-reactjs-7a6302c...](https://medium.com/@puppybits/immediate-mode-
reactjs-7a6302cd89cd)

~~~
flowerlad
I don't see parallels between OOP and retained mode, and functional and
immediate mode the way you are describing. UI components inherently have
state. Pretending they can programmed in functional style with stateless
functions is bizarre because UI functions do have side effects. See prior
discussion:
[https://news.ycombinator.com/item?id=24363261](https://news.ycombinator.com/item?id=24363261)

~~~
lukevp
Yes, ui components have state in the case of a retained mode GUI like the DOM,
but in the case of React, relevant data is derived from the application state
(eg IsDarkMode is a state property used to derive colors for a component, or
the checked state of a checkbox) and a unidirectional flow propagates that
state change to the VDOM on every re render. Functional doesn’t mean stateless
(state exists as closures within higher order functions, such as in the
composition of functional components within React), it means side-effect-free,
it means determinism in the derivation of additional state based on immutable
state updates.

~~~
flowerlad
> _Functional doesn’t mean stateless (state exists as closures within higher
> order functions, such as in the composition of functional components within
> React)_

Being stateless and side-effect free is pretty fundamental to functional
programming. If you can't replace a function call with its resulting value
(without changing the meaning of the program) then it is not functional
programming.

React is neither stateless nor side-effect free. Mapping it to concepts from
functional programming is counter-productive. You get something that is
neither fish nor fowl.

------
hashkb
See also: Let Over Lambda for more on this.

~~~
tines
+1. "Objects are a poor man's closure, and closures are a poor man's object."

~~~
srean
I understand the amusement value of this quote, but I never quite understood
what is so poor about a tuple of functions closed over same data into a
closure. Apart from inheritance, what does it lose. In fact its good that it
loses inheritance. Syntax of many OOP languages makes it way too easy to use
inheritance -- common things ought to be easy and potential design mistakes
hard.

~~~
Izkata
> but I never quite understood what is so poor about a tuple of functions
> closed over same data into a closure. Apart from inheritance, what does it
> lose.

In the closure-based version, getFullName and setFirstName are defined anew
for each instance of Person, using more memory each time. Typically isn't an
issue unless you're creating a massive number of them, but the class-based
version doesn't have this problem.

Also, just to throw it in the mix as well, the class-based version I believe
is largely just syntactic sugar over the traditional way of creating objects
in javascript, using prototype-based methods:

    
    
      function Person(firstName, lastName) {
        this.fName = firstName; 
        this.lName = lastName;
      
        return this;
      }
      Person.prototype.getFullName = function() {
        return this.fName + ' ' + this.lName;
      }
      Person.prototype.setFirstName = function(firstName) { 
        this.fName = firstName
      }
    
      const person = new Person("Ben", "Bitdiddle")
      person.getFullName()
    

Prototypical inheritance is interesting in that an instance of Person could be
used as the class for another object, ad infinitum.

~~~
wruza
An optimizing compiler could easily detect that a bunch of closures share an
upvalue block in an enclosing "constructor" and then instead make that block
explicit, and rewrite an entire constructor in a way that doesn't involve
multiple closures at all (given that escape analysis and lang rules allow
that). E.g.:

    
    
      // optimized
      function constructor(...) {
        let this = {...}
        function method(this, ...) {...}
        return function (name, ...) {
          switch (name) {
            case 'method': return method(this, ...)
              // or return a temp closure
              // like it does in tfa
    
      constructor()('method', 42)
    

And vice versa, on a computer that does closures in hardware better than
objects for some unrealistic reason.

That's why both are just _abstractions_ , whose semantics may better fit one
or another implementation, but it really doesn't matter for maths.

------
greenie_beans
would any devs want to start a book club for books like this? the article
mentions SICP, which is on my to-read list. it just seems so daunting. i'm
currently reading practical object oriented design in ruby by sandi metz.
would love to have somebody to discuss some books like this.

------
aaron-santos
Tangentially related is the idea that some OO constructs can be represented as
co-data. Previous discussion here
[https://news.ycombinator.com/item?id=24105755](https://news.ycombinator.com/item?id=24105755)

------
lolive
Classes is a semantic way of organizing your zillion of higher order
functions, that would otherwise be just floating around. Beans is the way to
build higher order data. Mixing them with care is the art of programming.

~~~
Joker_vD
God forbid the 'sin' function would be just floating around, outside of a
static 'Math' class. Or 'reduce', for that matter—obviously you need a special
'Reducer' class for that.

That reminds me of Steve Yegge's "Execution in the Kingdom of Nouns",
actually.

~~~
vblmark
A math module or namespace would be nice. Also for C headers I'd like to do
"from math.h import inf" to resolve conflicts with <cmath> and c++11 with non-
compliant implementations.

------
redPaper
that's one way of formulating it. another would be: classes are just a set of
methods with a common set of parameters (constructur) already applied (partial
application)

------
mrbonner
Isn't the function or OOO is just message passing?

------
duutfhhh
I see classes as nodes in the power grid that transmits and transforms data
instead of electricity. These nodes are wired up to other nodes via methods -
their binding points. To be precise, a class is more like a spec that can be
used to build an instance of that node. In some cases there's only one
instance.

The main advantage of classes, I think, is that they define one underlying
principle for all these data transformer nodes: that each node has a few
binding points with certain interface: named methods. The nodes don't have to
look this way, but restricting the freedom of design choices to this pattern
makes it easier to compose many nodes together. It's like setting the
expectation that all cars are squarish: it's easier to build the infra around
cars when you know how they can look in general.

------
leafboi
Ok. No. There's a lot of confusion with semantics. Following the most used
definition of OOP as defined by JAVA, C++ and C#:

Classes are in no way functions in the FP sense because classes mutate state.

Classes are in no way functions because calling methods requires the
instantiation of unrelated state. Example:

    
    
       class A
           def __init__(self, a, b, c):
              self.a = a
              self.b = b
              self.c = c
              self.banana = create_banana(create_gorilla(create_jungle()))
    
           def process_a(self):
              return process(self.a)
    

process_a cannot be used unless a, b, c and the banana plus the gorilla
holding the banana and the entire jungle the gorilla lives in is instantiated.

Let's talk about terminology. There are three that often get mixed up.

    
    
       Procedure = a set of instructions that could encompass mutating and changing state.
       Function = a box that when given input produces an output. The box cannot modify the universe. It can only produce something new when given an input. 
       Object = A grouping of a set of procedures and state that can mutate. 
    

The javascript programmer OP is mixing up function and procedure. He defines a
procedure and says that it can be a class. A procedure can be a class as it's
just a set of instructions which can encompass defining scope, state and more
procedures restricted to scope and state (aka an object).

This thing right here, written by the OP:

    
    
      function setFirstName(firstName) { 
        fName = firstName
      }
    

Is not a function... it is a method or a procedure that mutates state.

A function can do none of the above.

That's it.

~~~
bitdizzy
You're making an argument from definitions that would exclude ML from being a
functional language, which is absurd.

~~~
leafboi
No I'm using the mathematical definition of a function. ML is not Math nor is
it purely functional.

All functional languages need to bend the rules a bit in order to have side
effects but in general the person is not writing functions and therefore is
not getting the benefits of using functions.

FP is about reducing and restricting these functions that break the rules.
Defining a class in terms of mutations and side effects is going against the
philosophy of FP.

~~~
bitdizzy
> No I'm using the mathematical definition of a function.

 _Which_ mathematical definition? A "box" is not a mathematical definition.
There are multiple mathematically precise definitions of "function" possible.
Yours is none of them. Some of them accommodate objects that model mutable
state.

I don't think many (any?) PL theorists or functional programming practitioners
would agree with your dogmatic stance. Where are you coming from with all
this?

~~~
leafboi
I'm not having a dogmatic stance please stop voting me down. I'm tired of
juniors who think they know what they're talking about. Just stop.

[https://www.wikiwand.com/en/Function_(mathematics)](https://www.wikiwand.com/en/Function_\(mathematics\))

That is the definition of a function. Quite complex. I simplified the
explanation by using a Box. You will note in the wikipedia article they also
have a picture of a Box with inputs and outputs. That is the essence of
functional programming. Now please don't turn this into a immature pedantic
argument about some obscure definition of a mathematical function.

>I don't think many (any?) PL theorists or functional programming
practitioners would agree with your dogmatic stance. Where are you coming from
with all this?

Uh they do (and it's not a dogmatic stance, the definition of FP is quite
blurry, but immutability is universal). The point of functional programming
hence the name is for the programming to follow mathematical functions as
closely as possible.

In the ideal world your program in FP is just one giant pure function that is
a composition of other smaller functions. Of course your functions need to
have side effects so they come up with all kinds of tricks or bend the rules a
bit so that you can have things like IO and side effects but these are just
exceptions to the rule.

The philosophy of functional programming is to make your program as pure as
possible and minimize or segregate side effects away from your program as much
as possible.

This is essentially what and all that Haskell is. Haskell uses a trick, a VM
that takes an IO monadic Value and does side effects with it. Outside of that
VM all the user does to the program is write Pure functions and compose them
all together into a single function called Main. That's it.

That's literally what haskell is, and if you think PL theorists don't agree
with my "dogmatic" stance which is to say not "dogmatic" at all then you
really don't know what you're talking about because Haskell is basically
designed by the best in class functional PL theorists.

Let me put it simply for you.

If you can put your entire program in a single expression then you are doing
functional programming. That is what functional programming is. There are no
steps or procedures that happen one after the other. Every value is defined
permanently. There's no concept of time or procedures in functions that's why
you can't have variables getting assigned or mutated in FP.

You can only define things in functional programming as they are right now
without the concept of time in FP. Procedural programmers tend to create
buckets of empty data variables to be filled in over clock cycles.

If you don't get this, you don't understand functional programming.

In an expression, you cannot mutate values you cannot have procedures or
loops. Why do you think FP is loaded with recursion? If they allowed setters
and getters and mutation like the example then we might as well add a jump
command while your at it and suddenly we can use loops in functional
programming.

You just don't get it man. Dogmatic my ass, not even close.

~~~
stopachka
You have missed the point.

It’s curious you think this piece is written by a “JavaScript programmer”, and
the person who responded to you here is a “junior” — the implication being
that you know more.

It might help to take a step back and assume intelligence in others: what if
these people are smart? What could you learn from them? If you think the idea
is wrong, assume it’s coming from a peer. One way you know you are doing that,
is if you form your disagreement as a question.

—

I took the time to respond to you, because it looks like you have some real
love for programming, but know less than you think. You can grow a lot more if
you shift some of your thinking

~~~
leafboi
>You have missed the point.

Tell me what you think the point is. Typically when someone thinks a point was
missed they address the point rather than devolve the conversation into a
condescending description about my character and how I should act. It's a sort
of tactical what you're doing here. But who cares, no one is reading.

It's curious how you don't even address my points and just say that I missed
the point when I'm the one dictating the point in my original comment.
Typically this isn't how you respect other people and get them to respond
positively to your comments, what you're doing will draw other people to
support you but anger your target because of the condescension. I'm not sure
what you're objective is because people aren't really reading this thread...
it's already buried.

>It’s curious you think this piece is written by a “JavaScript programmer”,

The examples in the original piece are in javascript. Why don't you RTFA
before commenting on the "point."

>and the person who responded to you here is a “junior” — the implication
being that you know more.

The Junior thing was more of a retort. I said it with full awareness of what
it implies and how the other person would take it because his tone obviously
implies that he doesn't think he's a junior. Basically the replier has his own
opinion which he is entitled to say (and that I respect) but when you say
things like "dogmatic" and then vote me down... that's just not respectful.
Since I can't vote him down I inject a bit of subtle rudeness in my replies as
a subtle retort in return. Just being a mirror. Similar in a way to the subtle
game you're playing. That's all this is.

>It might help to take a step back and assume intelligence in others: what if
these people are smart? What could you learn from them? If you think the idea
is wrong, assume it’s coming from a peer. One way you know you are doing that,
is if you form your disagreement as a question.

Maybe you should take a step back and look at your own post. Telling people to
shift their thinking implies you have a sort of superiority complex. As if
you're not the one that's mistaken. How do you know I'm not a peer? How do you
know I'm not superior. Perhaps you should take a look at yourself. You seem
like a guy who thinks he's superior to me in programming but you haven't
demonstrated as much, you haven't even addressed the point.

You went on a side tangent talking about my behavior. Trust me, if you want
someone to change or listen to you, talking to them like this is not the path.

You want to know what will make people respond to you and listen to you?
Address them without any subtle disrespect. It's very simple.

You could've responded to me like this:

    
    
       I disagree with you. I also think there was a misunderstanding of the point. Here's why...
    

By proving the other person wrong without being disrespectful you can change
the other person's' character. But obviously this isn't our objective here is
it?

That being said take a look at this wikipedia post and tell me. Who missed the
point?

[https://www.wikiwand.com/en/Functional_programming](https://www.wikiwand.com/en/Functional_programming)

    
    
       "Functional programming is sometimes treated as synonymous with purely functional programming, a subset of functional programming which treats all functions as deterministic mathematical functions, or pure functions. When a pure function is called with some given arguments, it will always return the same result, and cannot be affected by any mutable state or other side effects. This is in contrast with impure procedures, common in imperative programming, which can have side effects (such as modifying the program's state or taking input from a user). Proponents of purely functional programming claim that by restricting side effects, programs can have fewer bugs, be easier to debug and test, and be more suited to formal verification.[1][2]"
    

Literally that's the definition I'm following. It's one form of the definition
and certainly a popular one. That's my opinion. You disagree? You think I
missed the point? Elucidate. The original poster can disagree but my opinion
is far from as he puts it "absurd."

Read the article. What definition of functional programming does that class
with a setter even fit under? Ok he redefined it as a higher order function...
Is what he doing procedural programming or functional programming. It looks to
me he's doing a bit of everything and calling it a function. Does the guy even
know that the class keyword is just sugar for "function" in javascript?

Look at this: [https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Classes)

Literally it says "classes" are just special functions. He's just reiterating
the javascript spec as if it's a new fangled discovery. In fact, before ES6
all "classes" were written with the keyword "function." No dude. The article
writer doesn't get it and neither does the person who responded to my post.
When you do OOP with LISP you're not doing FP period. The article writer just
noticed an isomorphism and is likely amazed by what all JS programmers were
doing before ES6. Not to be insulting but the parent poster likely doesn't
have much experience.

>I took the time to respond to you, because it looks like you have some real
love for programming, but know less than you think. You can grow a lot more if
you shift some of your thinking

I too took the time to respond to you. Despite your condescending
attitude/game. Let's see where this goes.

~~~
bitdizzy
If you decide to dismiss a position by saying that it chose the wrong
definition, you're not contributing anything useful. "Pure" functional
programming is not more functional programming than "Functional programming",
the adjective specializes it and makes it more narrow. I don't really care
what a wiki article says. I can run a survey of my colleagues if you want?

As for calling me a junior, well, you don't know how much experience I have,
do you? It's probably more than you, though. I've used and participated in the
development of functional programming languages for over a decade at this
point.

Unsolicited advice: Sophomoric pedantry isn't a good look.

~~~
leafboi
>Unsolicited advice: Sophomoric pedantry isn't a good look.

Starting conflict and calling people "dogmatic" and voting people down is not
a way to win people over. I can see a number of paths this road could have
gone down where you can easily get another person to agree with your ideas as
an alternative viewpoint despite a wikipedia article saying otherwise. You
chose to take none of these roads, maybe largely because you don't know how to
do this.

>I don't really care what a wiki article says.

Right because your opinion is the best opinion and only opinion that matters.
The community opinion and the majority opinion has no relevance to you because
you participated in "functional development for over a decade." Whoop dee doo.
I chose a definition of functional programming that has huge relevance to the
community at large. You on the other hand... haven't even stated your
definition yet.

Unsolicited advice: Arrogance and the inability to admit your own mistakes is
not a good look. A decade of experience does not earn you the right to act
like an ass hole nor does it make you a good programmer.

~~~
bitdizzy
You chose a definition among many and then dismissed the submission as
"confused" because it does not meet your definition.

I noted that your definition would preclude ML functions from being called
functions. Your response was that ML wasn't _purely_ functional, but that
doesn't make it not functional. The pure in "pure functional" doesn't "to the
exclusion of non-functional", it is simply a narrower category.

Considering that ML is one of the most impactful functional programming
languages both in theory and practice, I think it's right to call that absurd
and dogmatic. If you take it as a personal attack that I called your argument
absurd, I don't know what to say. Maybe grow a little bit of skin?

> You on the other hand... haven't even stated your definition yet.

I don't need to provide a definition to find a flaw in yours. I did not come
into this submission looking to smugly dismiss the topic at hand with my
obviously irrelevant preferences for terminology. You did.

~~~
leafboi
>You chose a definition among many and then dismissed the submission as
"confused" because it does not meet your definition.

My definition? I quoted wikipedia. A lot of people use "my definition"
Basically under "your" definition C++ and go might as well be a functional
programming language.

>Considering that ML is one of the most impactful functional programming
languages both in theory and practice, I think it's right to call that absurd
and dogmatic. If you take it as a personal attack that I called your argument
absurd, I don't know what to say. Maybe grow a little bit of skin?

Why grow skin? I literally didn't care. I just decided to call you junior
because you were acting like one. It seems like you cared more. I was just
explaining to the other guy why I called you a junior. I recognize the attack
but I literally don't care, but that doesn't mean I won't respond or address
it.

>I don't need to provide a definition to find a flaw in yours. I did not come
into this submission looking to smugly dismiss the topic at hand with my
obviously irrelevant preferences for terminology. You did.

My Definition doesn't have flaws. Like I said, if I expand it to encompass
mutability (as you have) then you can place Go and C++ on the functional
pedestal. I haven't used ML but clearly a language like ML only allows
mutability as a small exception that's rarely used otherwise there's no point
to classify ML as functional.

But let's get back on topic. You literally said that no PL theorist would
agree with me. But look at wikipedia. Apparently many do. So you're wrong.

~~~
bitdizzy
I don't take wikipedia to be authoritative about anything but I'll bite.

> Functional programming is sometimes treated as synonymous with purely
> functional programming, a subset of functional programming which treats all
> functions as deterministic mathematical functions, or pure functions.

Well, obviously in this context the author of the submission wasn't using that
definition. So you coming in and dismissing the conversation because
_sometimes_ people mean "pure functional programming" when they say
"functional programming" is clearly erroneous. I know when people make this
conflation, often when they're talking about Haskell. When talking about ML,
no one would take that synonym. Context matters.

I just looked, you provided a set theoretic definition of functions, the
wikiwand one. You chose a poor definition for the topic at hand. In most
mathematical settings it would be a perfectly fine definition, but not here.
Context matters.

Here are the problems with it: It assumes an interpretation in sets when there
are a plurality of interpretations of functions qua functional programming
which are not compatible with set theoretic models. For example, functions in
homotopy type theory have higher dimensional structure than just being
elements of a set. Functions in domains have more structure than just the
extensional mapping from inputs to outputs. Your chosen definition also
includes non-computable functions which are simply not admissible in this
context.

So your definition is simultaneously too restrictive and too lax.

You seem to be confused by the existence of multiple definitions and how they
are appropriate in context.

~~~
leafboi
>I don't take wikipedia to be authoritative about anything but I'll bite.

No but it's more authoritative than a random person on the internet (you). For
things like this it's good enough. I'm not writing a paper here.

>Well, obviously in this context the author of the submission wasn't using
that definition.

>Context matters.

>In most mathematical settings it would be a perfectly fine definition, but
not here.

In this context it's also perfectly fine. OP did not make a distinction
between subroutine or function. He also uses the term higher order function
wrong. It shows two things. He does not know what a higher order function is
and he does not know what a function is.

>Here are the problems with it: It assumes an interpretation in sets when
there are a plurality of interpretations of functions qua functional
programming which are not compatible with set theoretic models. For example,
functions in homotopy type theory have higher dimensional structure than just
being elements of a set. Functions in domains have more structure than just
the extensional mapping from inputs to outputs. Your chosen definition also
includes non-computable functions which are simply not admissible in this
context.

This is the garbage pedantry that I warned you about earlier. I'm choosing the
generally accepted academic definition. Hopefully you're not one of those
people who can't comprehend "generally accepted" without an expose into axioms
and different obscure branches of math.

>You seem to be confused by the existence of multiple definitions and how they
are appropriate in context.

Find the generally accepted definition in wikipedia that this person is using
(Hint: no actual technical definition exists). Obviously he's using "function"
in place of procedure or subroutine. But then he uses the term "Higher Order"
to imply an actual functions instead of procedures.

Not only does he use "Higher Order" incorrectly but his usage of the term
indicates he doesn't know what a function is and the difference between a
function and a procedure.

Yeah I'm not going to reply to your shit any more. HN really needs to change
the policy of not letting parent posters vote others down.

~~~
bitdizzy
> This is the garbage pedantry that I warned you about earlier. I'm choosing
> the generally accepted academic definition. Hopefully you're not one of
> those people who can't comprehend "generally accepted" without an expose
> into axioms and different obscure branches of math.

I think you should look into domain theory it is one of the most celebrated
discoveries pertaining to the semantics of functional programming languages.
And maybe you'll understand that from a programming point of view, what a
function is is much more flexible and subtle than you think.

> Yeah I'm not going to reply to your shit any more. HN really needs to change
> the policy of not letting parent posters vote others down.

Would it help if I pretended that you downvoted me? Every time I see my
imaginary internet points I will subtract 5.

~~~
leafboi
No you should just stop voting me down. I'm literally going to go negative
soon, I just joined. I literally cannot talk to you if you continue voting me
down. It's bad form.

>I think you should look into domain theory it is one of the most celebrated
discoveries pertaining to the semantics of functional programming languages.
And maybe you'll understand that from a programming point of view, what a
function is is much more flexible and subtle than you think.

Sure I could. But "context matters." This is not the topic of the
conversation. There's a level of depth we're operating at here. Very few
people understand "domain theory" and you shouldn't assume as much when you
communicate with anyone.

~~~
stopachka
Admittedly I downvoted this one:
[https://news.ycombinator.com/item?id=24438137](https://news.ycombinator.com/item?id=24438137)

Yet again though:

"Random person (you)" "he does not know what a function is." "Yeah I'm not
going to reply to your shit any more."

...give a good reason

\---

Anyways, leaving this thread. I certainly learned something from it, I hope
you did too! : )

I now noticed you're at -1, went ahead and gave you an upvote. Hopefully you
can still post, and be a bit more aware.

\--

Also, great work trying to explain bitdizzly. Def enjoyed reading your
explanations, and will explore some the references you popped in

~~~
leafboi
There's nothing for me to learn here other than domain theory which is very
advanced math and how people behave.

If you follow the conversation you'll see that the entire argument turned into
a battle of definitions with me turning to a very generally accepted
definition of a function and bitdizzy turning to using more obscure
mathematical definitions of "function" and arguments about semantics what
context is relevant to what definition of "function." Whatever definition you
choose to believe domain theory looks like very advanced stuff and clearly
outside the scope of your average technical conversation.

Either way, I didn't have time to respond to your other comment below. But I
will now.

Don't worry about the upvote thing. It's just for this thread I can switch
accounts.

