[racket] Code Reuse, Object Oriented vs Functional

209 views
Skip to first unread message

Scott Klarenbach

unread,
Jun 20, 2013, 2:53:05 PM6/20/13
to Racket mailing list
I'd like to get some feedback from the Racket group regarding Object Oriented vs Functional styles.  I know this can be a bit of a quagmire, so apologies if it's not appropriate to post it here.  I just thought I'm likely to get some of the more thoughtful replies from this group.

I've read the paper here: http://www.cs.rochester.edu/~cding/Teaching/254Fall2001/Assignments/tr98-299.pdf which outlines the central problem as having to choose between extensible variants (OO) and extensible tools (functional).  The paper proposes the extensible visitor pattern as a solution, and ultimately rests in the OO camp.  The next paper: http://www.ccs.neu.edu/racket/pubs/icfp98-ff.pdf goes a step further by showing how Racket specific features such as Units and Mixins can eliminate the need for the extensible visitor design pattern, and again, lands firmly in the OO camp.

In contrast, I've been playing a lot with Clojure and reading Rich Hickey (http://www.infoq.com/presentations/Value-Values and http://www.infoq.com/presentations/Simple-Made-Easy) and he proposes the opposite approach:  OO's time has come, and that through powerful functional languages you can achieve encapsulation, polymorphism and extensibility in a simpler manner without the complexity of OO techniques.

I'm curious as to the opinion of this community regarding Rich Hickey's stance on applying immutable values and pure functions to nearly every programming problem.

Regarding the first two papers discussing Object Oriented and Functional approaches to reuse, I'm wondering:

1.) Do generic functions (multiple dispatch) in a language not empower the functional arguments in the first two papers by Matthias and Matthew (and others)?  If I can add new functions with the same name that dispatch on new variants as they are added, is this not a simple solution to the extensibility problem in a functional style?  Does this not allow for reuse of both the original components and the existing clients?

2.) Does there exist an obvious class of problems that are better suited to an object oriented design vs functional and vice-versa, or is the power of such languages as racket reducing the OO vs Functional debate to a religious war, whereby both methods achieve reuse and it's just a matter of preference?

Thanks a lot.

--
Talk to you soon,

Scott Klarenbach

PointyHat Software Corp.
www.pointyhat.ca
p 604-568-4280
e sc...@pointyhat.ca
200-1575 W. Georgia
Vancouver, BC V6G2V3

_______________________________________
To iterate is human; to recur, divine

Grant Rettke

unread,
Jun 20, 2013, 3:16:13 PM6/20/13
to Scott Klarenbach, Racket mailing list
On Thu, Jun 20, 2013 at 1:53 PM, Scott Klarenbach <sc...@pointyhat.ca> wrote:
> both methods achieve reuse and it's just a matter of preference?

Agreed.
____________________
Racket Users list:
http://lists.racket-lang.org/users

Matthias Felleisen

unread,
Jun 20, 2013, 3:19:14 PM6/20/13
to Scott Klarenbach, Racket mailing list

1. Yes, extensible dispatch allows for elegant solutions of the 'extensibility problem' that we worked on in the 1990s. Manuel Serrano pointed that out in '99 and again in '00, and by coincidence, we discussed this today in a meeting on generics.

2. Choose depending on your existing context (language, ide, tools) and needs (how much extensibility do you need now?). If you are writing a product from scratch, choose a tool chain whose language allows and supports FP, class-based OOP, and generics programming. Answering this question in the abstract is a bad idea.

You may wish to check out the generics library in git head (developed by Eli, Vincent, Asumu, and Claire -- a kind of historic order) to see whether it fits your needs.


-- Matthias

Asumu Takikawa

unread,
Jun 20, 2013, 3:42:16 PM6/20/13
to Matthias Felleisen, Scott Klarenbach, Racket mailing list
On 2013-06-20 15:19:14 -0400, Matthias Felleisen wrote:
> You may wish to check out the generics library in git head (developed
> by Eli, Vincent, Asumu, and Claire -- a kind of historic order) to see
> whether it fits your needs.

Side note: any version v5.3 or later of Racket has the `racket/generic`
library, so you don't need git HEAD unless you want to try the newest
features.

Cheers,
Asumu

Sean Kanaley

unread,
Jun 20, 2013, 3:42:53 PM6/20/13
to us...@racket-lang.org
The definition and essence of "object" is not always agreed upon (encapsulation, polymorphism, state, ...), but since you're wondering about objects versus functions (purely functional), the "versus" implies a difference about an object that makes it impure, or the comparison isn't so helpful.  If an object was simply an enhanced pure function it would just be better.  So the key is that it is impure.

In terms of your first question, multiple dispatch is therefore a different kind of concern (polymorphism) than the opposing difference between object and function (purity).  One can achieve polymorphism either through doing something different based on argument types (multiple dispatch) or doing something different based on the actual type of thing being operated on (sub-object type of generic object method--single dispatch).

If you're doing collision detection, multiple dispatch is useful.  You can write something like "(cartesian-prod collide? objects)" which presumably passes every object paired with every other object to collide?, which depending on the object types, handles the collision appropriately (e.g. friendly fire is disabled by not detecting player missiles hitting friendly infantry).

If instead you want to accelerate a vehicle, you can use the vehicle itself with its polymorphic accelerate method "(send vehicle accel)" to accelerate either a motorcycle or truck without caring what the actual subtype is.  The thing is, multiple dispatch generalizes this (multiple dispatch generalizes single dispatch clearly...).  The vehicle acceleration is also handled by a multimethod that could be called "(accel vehicle)".  It's like collision detection in that it accelerates based on the argument type--there just happens to be exactly one argument.

So there's really nothing special about objects and polymorphism *gasp* as they are just a gimped way of dispatching compared to multimethods!  This brings us back to state.  An object (really a closure) is useful because it contains state (so does a plain "structure" type, so arguably I'm implying the encapsulation is useful as well).  If one is attempting to maximize the use of an object/closure, it seems they would have to take advantage of this state.  So one would use an object not so much for "extensibility" (which is inferior to the kind granted by multiple dispatch) but for mutable state.

I must therefore conclude objects are for things like simulations and other real-time, especially interactive applications where things change over time.  There is also functional-reactive programming, which aims to bring "pure state" through functions that take time as an implicit parameter, and this has advantages and disadvantages (space/time leaks, sometimes getting infinite loops from difficulty reasoning about whether an update affects something "immediately" or in the next full "update cycle" (e.g. Yampa has both various switches and various comparable delayed switches to implement either)).  But ultimately, if one is choosing an object-oriented approach, they should be doing it for the mutable state (or at least encapsulation).

If you just want polymorphism, multiple dispatch is flat out more powerful.

Greg Hendershott

unread,
Jun 20, 2013, 5:35:14 PM6/20/13
to Scott Klarenbach, Racket mailing list
Just last week I stumbled across this:

"Solving the Expression Problem with Clojure 1.2
Extend preexisting types to new methods, and preexisting methods to new types"

http://www.ibm.com/developerworks/library/j-clojure-protocols/

If that resonates with you, then someone more knowledgable than me
about Clojure might be able to map that onto the similar concepts in
Racket. (Such as, "protocols and multimethods are like generics", and
"defrecord and deftype are like ___".)


p.s. Personally? I spent many years doing OOP in C++. Lately I'm
functional-ish in Racket (to the point of blatantly ignoring the class
portion of Racket). Sometimes the pendulum has to swing to the other
extreme before settling in the middle, just not yet for me in this
case. However if I were doing GUI or simulation things, I'd probably
be leaning back toward OOP for that.

Neil Van Dyke

unread,
Jun 20, 2013, 7:17:24 PM6/20/13
to Scott Klarenbach, Racket mailing list
Anecdotal...

Racket is a powerful general-purpose algorithmic language, including a
bunch of great facilities for mini-languages, plus some standard
libraries (like "racket/class") that support different ``paradigms''.

Early in my career, I did a lot of industry R&D work on methodology and
CASE for OO analysis/design/programming, as well as a lot of practical
work using those same methods and tools. So it was surprising to me to
find myself no longer using even an OOPL nor always decomposing the
world into a class-instance object model.

Nowadays, doing most of my development in Racket, I never use Racket's
OO library, but instead pick&choose conceptual constructions from
various different ``paradigms'', and implement them using basic Racket
features. For example, in the code I am working on in another window --
which generates a startup's Web site -- I think of the pages as objects,
but actually implement them using Racket "struct"s, and populated via a
minilanguage, with all the metadata and content embedded in the Racket
source file. The code is in a functional-esque style, with almost no
mutations, but I am also conscious of the algorithmic evaluation model.
The bodies of the pages -- separate from the metadata and stock parts --
is marked up in a minilanguage that is s-expressions that is SXML with
some non-SXML bits added to it: shorthands for things like referring to
particular pages by ID, and special URI objects (absolute URI that are
automatically translated to minimal URI relative to the URI of the page
in which they are referenced). The site has a
programmatically-generated navigation bar that works in a desired way
that off-the-shelf ones probably couldn't do. This is a small program,
and I just banged it out quickly to suit the task, not spent weeks on
it. It sure beats using some big ``enterprise framework'' that wants
things done in a bloated and bureaucratic manner yet doesn't really do
what I want.

Neil V.

Ray Racine

unread,
Jun 21, 2013, 9:39:12 AM6/21/13
to Scott Klarenbach, Racket mailing list
Speaking from a reasonable amount of experience in "real-world" composing code in a polyphony of styles, idioms, methodologies and languages, I have reached a few (personal) conclusions. 

1) Functional vs OO -> Functional by a landslide where the critical factors are Code Correctness, Maintainability, Understandability, Succinctness, Changeability.
    Here it really comes down to state, minimization of, reduction of redundant state and above all limiting state mutation.

2) Pure Functional vs Functional with side effecting escape hatch. -> Functional with escape hatch.
   Haskell / Monadiac IO is too limiting and often contorts the code needlessly or for questionable gain.  Yea, basic IO is OK.  But as soon as things get real world and you have to start pulling out nested monadic computations via monadic transformers yada yada pain thresholds are breached and silent screaming erupts.  In a functional language, it is very easy to cleanly modularize code and specifically to modularize IO from pure referentially transparent functional code.  i.e. You can get pretty much all the gains without the pain with only a bit of personal discipline.

3) Static Typed vs Dynamic Typed (loosely term) vs Hybrid -> Hybrid will win hands down.
    I don't understand the contentious debate on this at all, not a whit.  It is simply foolish, plain, pure and simple to NOT leverage static analysis of code, i.e. type check.  Seriously, if you are not placing the one liner type signature along with every Racket procedure you write, start.  Sure, cheat for that 50 line Racket script, but otherwise no excuses. 

The future will be hybrid with the agenda being set by Racket and shadows such as Dart.  The appropriate mixture of reasonable static checking along with runtime contract assertions for those things which cannot be reasonably statically asserted will be foundational moving forward.

  So for example, ne area where functional programming really hits its stride when one starts to leverage HOFs (functions taking functions, returning functions).  It's a whole new world.  Eventually small towers of HOFs generating HOFS, used by plain ol' Fs happen.  Such constructions without the safety of static scaffolding is just ... darn foolish.

4) The Expression Problem
   For whatever reason one can code in OO without ever noting the expression problem.   After a bit of functional programming you note it, even if you don't know what it's been called or the dual nature of the issue in OO land.  Once you know of it you'll start noting its dual side in OO.

I think the biggest hole in Racket at the moment and I can't think if any other (largish hole) has to do with (pick one or more from 0-3 and add 4):

 0) type classes
 1) typed multimethods / generics
 2) typed protoypes (a la Closure)
 3) typed interfaces for structures, a la Go.
--------------------------------------------------------------
 4) typed sigs/units.

Off the cuff 3 + 4 would be HUGE and sufficient alone (for me)



On Thu, Jun 20, 2013 at 2:53 PM, Scott Klarenbach <sc...@pointyhat.ca> wrote:

Hendrik Boom

unread,
Jun 21, 2013, 9:55:55 AM6/21/13
to us...@racket-lang.org
On Fri, Jun 21, 2013 at 09:39:12AM -0400, Ray Racine wrote:
...
>
> 4) The Expression Problem
> For whatever reason one can code in OO without ever noting the
> expression problem. After a bit of functional programming you note it,
> even if you don't know what it's been called or the dual nature of the
> issue in OO land. Once you know of it you'll start noting its dual side in
> OO.
...

Care to describe the Expression Problem and its dual? I'm not
familiar with the term.

-- hendrik

Ray Racine

unread,
Jun 21, 2013, 11:23:24 AM6/21/13
to Hendrik Boom, Racket
The Internet is rife with stuff regarding the Expression problem.  Pretty much any major language has some posting, paper or article on how it is addressed to some degree by the language in question.

http://en.wikipedia.org/wiki/Expression_problem

It's a can I have my cake and eat it too issue.

"add new cases to the datatype and new functions over the datatype, without recompiling existing code, and while retaining static type safety"

You sorta get one and not the other respectively in Functional vs OO.  The trick is we all want both damn it.

FWIW, Scala with its "Type Class" and implicit conversions gets fairly close, but its a bit heavy handed.

Scott Klarenbach

unread,
Jun 21, 2013, 1:43:24 PM6/21/13
to Racket mailing list
Thanks a lot for the responses.  I really appreciate it.

It's reassuring to hear many of my assumptions echoed back.  And the mention of the Expression Problem has led me to uncover additional articles on the topic besides the original Krishnamurti, et al paper.

Scott.

Todd O'Bryan

unread,
Jun 21, 2013, 2:57:21 PM6/21/13
to Scott Klarenbach, Racket mailing list
Whoa! I had no idea that Shriram and the rest of the Rice group were
the impetus for the distillation/clarification and naming of "The
Expression Problem." I'm continually amazed that I've had a chance to
interact with people who've had such a fundamental impact on the
field. And because I came to know them through HtDP, the awe I feel
about their pedagogical acumen is just reinforced every time I hear
about one of these connections.

To wit, a former student was interviewing with Asana, one of the hot
Silicon Valley start-ups. When I asked what was interesting about what
they do, he pointed me toward FlapJax, and I was able to say, "Yeah,
one of the co-authors also co-wrote that Intro to Programming textbook
you went through nine years ago."

Todd

Shriram Krishnamurthi

unread,
Jun 21, 2013, 8:27:06 PM6/21/13
to Todd O'Bryan, Scott Klarenbach, Racket mailing list
On Fri, Jun 21, 2013 at 2:57 PM, Todd O'Bryan <toddo...@gmail.com> wrote:
> Whoa! I had no idea that Shriram and the rest of the Rice group were
> the impetus for the distillation/clarification and naming of "The
> Expression Problem."

To set the record straight, since this is a public forum:

We (Matthias and I) called it the "Expressivity Problem" and
circulated it amongst many people. We also tracked down many other
prior papers that at least alluded to this issue, though the version
we presented also extends some of these. (Some papers that claim to
"solve" the problem actually do not address the problem as fully
formulated in our paper.)

Phil Wadler heard about the problem from us at ECOOP 1998, where our
paper appeared and which he attended. He initially did not believe
there was a problem, but we clarified this at the q&a of the paper
presentation. We discussed it further the next day on the subway. He
eventually agreed it was a problem worth publicizing as a challenge.

However, he felt our name was too vague and too broad. He therefore
came up with the name "Expression Problem", which is a very nice pun
(expression = "how much can your language express", and expression =
"the terms you are trying to represent are language expressions"). So
the credit for the name very much goes to Wadler.

Shriram

Bardur Arantsson

unread,
Jun 21, 2013, 3:42:29 PM6/21/13
to us...@racket-lang.org
On 06/21/2013 05:23 PM, Ray Racine wrote:
> The Internet is rife with stuff regarding the Expression problem. Pretty
> much any major language has some posting, paper or article on how it is
> addressed to some degree by the language in question.
>
> http://en.wikipedia.org/wiki/Expression_problem
>
> It's a can I have my cake and eat it too issue.
>
> "add new cases to the datatype and new functions over the datatype, without
> recompiling existing code, and while retaining static type safety"
>
> You sorta get one and not the other respectively in Functional vs OO. The
> trick is we all want both damn it.
>
> FWIW, Scala with its "Type Class" and implicit conversions gets fairly
> close, but its a bit heavy handed.

Just for the record, Scala wasn't the origin of the type class concept
-- it originates in Haskell. (Btw, Scala people tend to refer to it as
"typeclass" to avoid ambiguity with "type" and "class" both of which are
entirely separate concepts in Scala.)

AFAICT both Haskell and Scala's type classes *fully* solve the
expression problem, but maybe I'm missing something... care to enlighten
us what's missing? (as implied by your "gets fairly close")

Regards,
Reply all
Reply to author
Forward
0 new messages