Mapping OOPS concepts to Clojure? Doable or Wrong thinking?

23 views
Skip to first unread message

ajay gopalakrishnan

unread,
Dec 12, 2009, 8:13:28 AM12/12/09
to clo...@googlegroups.com
Hi,

I come from a OOPS (Java) world and I am used to Singletons, Inheritance, Statics, Interfaces etc.
I am reading the Programming Clojure book and I understand multi-methods and when it is used.
But I am still not able to see how to achieve the effects of Singletons, Inheritance, Statics, Interfaces etc. in Clojure. If the book explains it somewhere, I would be glad to get a pointer to that too.
When I say "achieve the effects" , I am not asking if there is a way to define a Singleton class etc. I am asking that if the design in my head has all these things, how would I translate that into Clojure (some way or the other) or what modifications would need to be made to my design (in my head) to able to directly write it in Clojure terms.

Thanks,
Ajay G.

Sean Devlin

unread,
Dec 12, 2009, 11:03:55 AM12/12/09
to Clojure
Ummm.... some of these thing DON'T map to Clojure.

I'd suggest you check out Rich's videos here:

http://blip.tv/file/982823

Anyway, as to how you would solve some of these problems in Clojure...

Static methods you get for free, because everything is a function in
Clojure.

Singletons aren't really required, because using a keyword generally
gets the same effect. You can also use a memoize function to prevent
expensive things being created more than once.

As far as Inheritance & Interfaces are concerned... well, uh... those
generally aren't used in Clojure. Personally, I use a lot of maps
where I used to use objects. I've found that I like my code better
now.

Others might have some other ideas on how to com from Java to Closure.

Sean

David Nolen

unread,
Dec 12, 2009, 11:11:40 AM12/12/09
to clo...@googlegroups.com
On Sat, Dec 12, 2009 at 11:03 AM, Sean Devlin <francoi...@gmail.com> wrote:
Ummm.... some of these thing DON'T map to Clojure.

I'd suggest you check out Rich's videos here:

http://blip.tv/file/982823

Anyway, as to how you would solve some of these problems in Clojure...

Static methods you get for free, because everything is a function in
Clojure.

Singletons aren't really required, because using a keyword generally
gets the same effect.  You can also use a memoize function to prevent
expensive things being created more than once.

As far as Inheritance & Interfaces are concerned... well, uh... those
generally aren't used in Clojure.  Personally, I use a lot of maps
where I used to use objects.  I've found that I like my code better
now.

Inheritance & Interfaces can be achieved via multi-methods and types. Also checkout deftype and defprotocol work in the new branch.


Others might have some other ideas on how to com from Java to Closure.

Sean

On Dec 12, 8:13 am, ajay gopalakrishnan <ajgop...@gmail.com> wrote:
> Hi,
>
> I come from a OOPS (Java) world and I am used to Singletons, Inheritance,
> Statics, Interfaces etc.
> I am reading the Programming Clojure book and I understand multi-methods and
> when it is used.
> But I am still not able to see how to achieve the effects of Singletons,
> Inheritance, Statics, Interfaces etc. in Clojure. If the book explains it
> somewhere, I would be glad to get a pointer to that too.
> When I say "achieve the effects" , I am not asking if there is a way to
> define a Singleton class etc. I am asking that if the design in my head has
> all these things, how would I translate that into Clojure (some way or the
> other) or what modifications would need to be made to my design (in my head)
> to able to directly write it in Clojure terms.
>
> Thanks,
> Ajay G.

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Joost

unread,
Dec 12, 2009, 12:21:31 PM12/12/09
to Clojure
Hi Ajay,

Trying to translate from "traditional" OO concepts to functional
constructs is not always useful, and I'll try to explain why. When I
started writing this it sort of turned into a critique of fixed-type
class-based OO (the kind of thing you find in Java and C++) - I'm
sorry if you're not really interested in that. :)

1. Many of the concepts are there ONLY because there is no straight-
forward means of implementing them if you have to state everything in
terms of classes and objects. Examples:

* Static members/methods: these are almost always just a way of
defining global functions and variables. The exception is when you
have multiple classes that implement the same static members and you
pass around the classes to get different values for the same member
names, but while this is a useful technique, it's actually not
something I've seen used in any Java program I've looked at - in my
experience, that sort of technique is used a lot more in more dynamic
OO languages that emphasize "reflection" or "meta-programming" (which
are both concepts that also seem to be solutions to the traditional
OO problems instead of radically novel concepts).

* Singletons are nothing more than functions that always return the
same object or value. You can even implement them just as a global
variable. In my experience, actual singletons as put forth in the gang
of four book are often mistakes brought about by a lack of
imagination.

* Interfaces are a way to deal with the fact that in traditional OO
systems, you can't treat unrelated classes the same way. The fact that
you can use interfaces to explicitly document the way your classes
work is nice but incidental. Many more dynamic OO languages (and
'basic' clojure) don't have or need interfaces since they just check
the existence of a member or method at runtime.

* Inheritance is overrated. it tends to be abused as a way to share
implementation details more than anything else. All the points I made
about interfaces also apply to inheritance. See also traits, for a way
to really do reuse: http://scg.unibe.ch/research/traits

2. In my mind, the single most important use of OO is polymorphism.
The ability to associate functions with multiple implementations
depending on their parameters is very useful since it means you can
generalize algorithms without having to know the implementation
details of the data that's passed in. Clojure has a couple of ways to
do this; multimethods are just one of the more explicit constructs.

3. Classes in particular are difficult concepts in Java-style OO.
Classes tend to be not really objects for one: you can't easily pass
around a class and construct instances of it later - hence Factory
methods and reflection APIs. You also can't construct new classes at
run-time, but at the same time, the language strongly suggests you to
map certain concepts to classes. Both problems are much easier dealt
with in a more dynamic language like JavaScript or Ruby, but in Ruby
especially, there seems to be a risk of turning everything in sight
into a dynamically constructed class.

In conclusion, try to forget about OO for now and see how far you can
get using just "really functional" constructs, like closures and
higher-level functions. It's sometimes amazing to see how much cleaner
and simpler the results of a functional approach can be when compared
to objects and classes, but it does require a very different mindset -
do not try to map directly from classes and objects to functions; it
will only confuse. In my experience, it's more useful to think in a
higher level of abstraction - a set of components to do this part of
the code, and another to do that part. For instance, you can easily
implement a Model-View-Controller system functionally, but that is
because Model, View and Controller are NOT objects; they're distinct
sets of responsibilities. Software "patterns" at that level of
abstraction are useful even in a non-OO language, but you can't
directly translate their implementations.

ajay gopalakrishnan

unread,
Dec 12, 2009, 2:33:22 PM12/12/09
to clo...@googlegroups.com
@Joost ,
Excellent Description. Of the sort that I was really hoping for! Indeed a heavy meal to digest, for an OOP person, but I see your point.

Thanks!
Ajay


--

Michael Wood

unread,
Dec 12, 2009, 3:41:39 PM12/12/09
to clo...@googlegroups.com
Hi

2009/12/12 ajay gopalakrishnan <ajgo...@gmail.com>:
I think it might be easiest to try implementing something and then ask
here or on IRC if you get stuck or if you want to know a more
idiomatic way to do it.

--
Michael Wood <esio...@gmail.com>

mbrodersen

unread,
Dec 12, 2009, 7:10:22 PM12/12/09
to Clojure
There is nothing "wrong" about objects in Clojure as long as the
objects are immutable.

Some people tend to think that "functional" is anti-"object oriented".
That is IMHO the wrong way to think. They complement each other. Why
limit the tools in your toolbox? F# (for example) shows how it can be
done elegantly.

Here is one (quick and dirty done in 5 min) way of using objects in
Clojure that (again IMHO) is fully compatible with the "Clojure style"
of programming because the objects (maps) are immutable:

(defmacro ? [object value]
"Get an object value - same as object.value in OO but immutable"
`(get ~object (keyword (str '~value))))

(defmacro ! [object method & args]
"Call an object method - same as object.foo(); in C# but immutable"
`((get ~object (keyword (str '~method))) ~object ~@args))

(defmacro != [object name value]
"Set an object value - same as object.value = foo; in OO but
immutable"
`(assoc ~object (keyword (str '~name)) ~value))

(defmacro !fn [object name fn & args]
"Execute a function on an object value and sets the object value to
the result - roughly same as using mutable object but done in an
immutable style"
`(assoc ~object (keyword (str '~name)) (~fn (get ~object (keyword
(str '~name))) ~@args)))

mbrodersen

unread,
Dec 12, 2009, 7:18:49 PM12/12/09
to Clojure
Cleaned it up a bit:

(defmacro ? [object value]
"Get an object value - same as object.value; in C# but immutable"
`(get ~object (keyword (str '~value))))

(defmacro ! [object method & args]
"Call an object method - same as object.method(args); in C# but
immutable"
`((get ~object (keyword (str '~method))) ~object ~@args))

(defmacro != [object name value]
"Set an object value - same as object.name = value; in C# but

Travis

unread,
Dec 13, 2009, 2:01:42 AM12/13/09
to Clojure


On Dec 12, 9:21 am, Joost <jo...@zeekat.nl> wrote:
> * Inheritance is overrated. it tends to be abused as a way to share
> implementation details more than anything else. All the points I made
> about interfaces also apply to inheritance. See also traits, for a way
> to really do reuse:http://scg.unibe.ch/research/traits

I haven't read all the literature on traits, but I've begun using a
pattern in Clojure that resembles the concept. This is a pseudocode
sketch (don't try to execute), but I hope gets the pattern across.

(def trait-a {
:do-something (fn do-something [applied-to & params]
(using applied-to (mutate params)))
})

(defn apply-trait [trait apply-to]
(into {} (map
(fn make-applied-trait-method
[fn-symbol trait-fn]
[fn-symbol (partial trait-fn apply-to)])
trait)))

You'd use this like:

(let [
trait-a-data (struct-map struct-i-use
:datafield1 1 :datafield2 2)
specific-fns (apply-trait trait-a trait-a-data)
]
((specific-fns :do-something) to-something))

Have other people done similar things, or have an improvement?

Raoul Duke

unread,
Dec 13, 2009, 2:12:59 AM12/13/09
to clo...@googlegroups.com
hi,

> 2. In my mind, the single most important use of OO is polymorphism.
> The ability to associate functions with multiple implementations
> depending on their parameters is very useful since it means you can
> generalize algorithms without having to know the implementation
> details of the data that's passed in.

this probably isn't the right list to get into such things, but... :-)

i think that polymorphism here would need to be better defined since
there are many kinds of it, and that a lot of polymorphism doesn't in
any way have to be anything about OO at all. i'm just trying to warn
against believing 'OO bijection Polymorphism' or some such.

sincerely.

Laurent PETIT

unread,
Dec 13, 2009, 6:32:50 AM12/13/09
to clo...@googlegroups.com
Unless I've missed something implicit in your post, why do present us (and particularly ajay, who's trying to understand the language) what I would consider an abuse of macro, where regular functions would do the job very well ?

2009/12/13 mbrodersen <morten.b...@gmail.com>

Laurent PETIT

unread,
Dec 13, 2009, 6:39:22 AM12/13/09
to clo...@googlegroups.com
Ajay,

It seems to me your questions are totally justified. It's a normal reaction to try to make links between things you know and things you discover. Fortunately, the world doesn't expect you to forget everything you've done in the past in order to try new other things.

Your questions, to be answered well (in deep detail, not just at the surface of things, and with sufficient examples so that you just feel "dump", with answers like "I know how to do, you'll eventually know too" - sort of -), would deserve a book on its own : "From java to clojure : Design patterns revisited", or something like that.

The problem is, from each thing you pointed, one needs to go back to the underlying need, and from that need, go back to the underlying software principle. And then, from that, one can derive the software principle in clojure, show the several ways to do, etc. ....

So there's really no problem with your questions, apart the fact that they're certainly too general to get a comprehensive answer.

I (as other already did in this thread) encourage you to experiment with some concrete examples. It will be easier for you to get precise answers.

HTH,

--
Laurent

2009/12/12 ajay gopalakrishnan <ajgo...@gmail.com>
--

Laurent PETIT

unread,
Dec 13, 2009, 6:41:24 AM12/13/09
to clo...@googlegroups.com
And I encourage you to do so: everything that can help bridge the gap between "Java's way of programming things" and "Clojure's way of programming things" will be benefitial to everybody.

2009/12/13 Laurent PETIT <lauren...@gmail.com>

ajay gopalakrishnan

unread,
Dec 13, 2009, 9:59:32 AM12/13/09
to clo...@googlegroups.com
Thanks to all,
Yes, I am going through the book now and learning the rules of the game. Once I am done with it, I will post on this list, some code (which I will believe to be the Clojure way of doing things) and ask if that seems to be the idiomatic way of doing things.
I strongly feel though that either the book or the website should have something in place to make the transition easier. And I think doing this by small complete applications would be the best way to go.

Something like these sites, that show converting imperative procedural code to functional
http://blog.bestinclass.dk/
http://clj-me.cgrand.net/
but something focusing more on the bridging OOPS & Functional.

Thanks,
Ajay G.

Joost

unread,
Dec 13, 2009, 12:58:41 PM12/13/09
to Clojure
Of course you don't need OO to do polymorphism, and I'm fairly sure
that OO doesn't do polymorphism the best way, but in my estimation the
main reason "classic" OO is so popular is that it provides a very
concrete way to do polymorphism easily.

In the same way, you can do "functional" (side-effect free) code with
objects too. They're not mutually exclusive. It's just that doing
stuff side-effect free pretty much forces you to drop many of the
classic OO patterns.

Raoul Duke

unread,
Dec 13, 2009, 1:48:36 PM12/13/09
to clo...@googlegroups.com
> objects too. They're not mutually exclusive. It's just that doing
> stuff side-effect free pretty much forces you to drop many of the
> classic OO patterns.

seems to me that a lot of it comes down to connotations vs.
denotations; what /is/ OO, anyway? :-)

sincerely.

Joost

unread,
Dec 13, 2009, 3:03:53 PM12/13/09
to Clojure
On 13 dec, 19:48, Raoul Duke <rao...@gmail.com> wrote:
> seems to me that a lot of it comes down to connotations vs.
> denotations;

I really don't know what you mean by that.

> what /is/ OO, anyway? :-)

From what I've seen, it's the association of function implementations
with a complex type or data structure.

Richard Newman

unread,
Dec 13, 2009, 3:19:12 PM12/13/09
to clo...@googlegroups.com
> Of course you don't need OO to do polymorphism, and I'm fairly sure
> that OO doesn't do polymorphism the best way, but in my estimation the
> main reason "classic" OO is so popular is that it provides a very
> concrete way to do polymorphism easily.

At the risk of going off on a bit of a tangent:

My experience with teaching OO to university students (and watching my
own class learn it) suggests that polymorphism -- at least, as
presented by C++ and Java -- is the hardest concept for beginners to
grasp.

Encapsulation and some (usually erroneous) notion of 'modeling the
world' would seem to be the most obvious improvements over structured
programming, and beginners pick those up easily. When you present a
scenario of some object representing a bank account, "owning" its
balance and providing an interface to access it, OO seems a natural
fit to the problem. Polymorphism builds on that, yes, but one could
have a useful OO system without it (e.g., the various approaches to OO
in C, such as putting function pointers in structs, or prototype-based
OO systems).

I suspect that students' difficulty with "traditional" OO polymorphism
has something to do with having to hold the inheritance hierarchy in
their heads while also looking at the instance, and figuring out what
will happen. At that larval stage it's a lost cause to dive into
virtual function tables :)

I'd be interested to see how Clojure's multimethods -- which pull out
the dispatch function into a concrete thing -- fare by comparison. As
with a lot of things, having a REPL there and being able to call the
dispatch function on various inputs would be a massive aid to
understanding.

Joost

unread,
Dec 13, 2009, 7:23:20 PM12/13/09
to Clojure
On 13 dec, 21:19, Richard Newman <holyg...@gmail.com> wrote:
> At the risk of going off on a bit of a tangent:
>
> My experience with teaching OO to university students (and watching my  
> own class learn it) suggests that polymorphism -- at least, as  
> presented by C++ and Java -- is the hardest concept for beginners to  
> grasp.

I would probably say that that is because it is the most powerful
aspect of OO. Power is hard to wield effectively.

> Encapsulation and some (usually erroneous) notion of 'modeling the  
> world' would seem to be the most obvious improvements over structured  
> programming, and beginners pick those up easily. When you present a  
> scenario of some object representing a bank account, "owning" its  
> balance and providing an interface to access it, OO seems a natural  
> fit to the problem. Polymorphism builds on that, yes, but one could  
> have a useful OO system without it (e.g., the various approaches to OO  
> in C, such as putting function pointers in structs, or prototype-based  
> OO systems).

Oh yes, OO demands a kind of view of the problem that helps in
breaking it down into manageble items, but it's not easy. In fact, I
think it's actually hard to design an object-based system that models
a problem well - in the general case - and the main reason we as
programmers feel comfortable with OO is that we're so used to it. In
the same way we tend to feel comfortable with relational databases -
they're both a help in that they give you a pretty clear way of
deciding what "works" and what doesn't, but at the same time, they can
force all kinds of restrictions and work-arounds that are completely
artificial.

Encapsulation as in access control is really quite incidental and only
marginally helps you in making sure the program works as expected -
but neophytes to OO seem to think that that is the main benefit -
while you can do encapsulation and API "contracts" in any language
that has functions. I've commented in the past that whoever thought up
"protected" should be publicly shamed.

That's not to say that "pure functional" programming is better. As a
general design principle, I would say it is, but you'll still run into
problems where maybe OO has the better tools or the more straight-
forward means of mapping a problem to code.

> I suspect that students' difficulty with "traditional" OO polymorphism  
> has something to do with having to hold the inheritance hierarchy in  
> their heads while also looking at the instance, and figuring out what  
> will happen. At that larval stage it's a lost cause to dive into  
> virtual function tables :)

Inheritance is at the same time too powerful and too weak. Look at any
large Java project's API docs and try to figure out what the hell is
happening. It just doesn't work for anything that isn't fundamental or
clearly restricted. It's just not a good way of handling the larger
problems. See the number of Java classes named XXXworker/actor/factory/
builder etc. Those things aren't objects; they really are just a bunch
of functions. I think it's actually harmful when the language forces
OO upon you because that kind of thinking can cloud the intent of
whatever it is you're trying to build.

> I'd be interested to see how Clojure's multimethods -- which pull out  
> the dispatch function into a concrete thing -- fare by comparison. As  
> with a lot of things, having a REPL there and being able to call the  
> dispatch function on various inputs would be a massive aid to  
> understanding.

At the very least, explicit dispatch functions force you to think
about what you're doing. That's probably a good thing. In my
experience, you really don't need them much at all though. As with
"standard" polymorphism, it's a great tool when it fits - especially
when designing general libraries - but it's not something you need
much in day-to-day programming, except - maybe - as a way to deal with
name clashes.

mbrodersen

unread,
Dec 14, 2009, 3:04:23 AM12/14/09
to Clojure
"an abuse of macros?"

HAHAHA you are funny Laurent :-)

On Dec 13, 10:32 pm, Laurent PETIT <laurent.pe...@gmail.com> wrote:
> Unless I've missed something implicit in your post, why do present us (and
> particularly ajay, who's trying to understand the language) what I would
> consider an abuse of macro, where regular functions would do the job very
> well ?
>
> 2009/12/13 mbrodersen <morten.broder...@gmail.com>
> > clojure+u...@googlegroups.com<clojure%2Bunsu...@googlegroups.com>

Laurent PETIT

unread,
Dec 14, 2009, 3:32:40 AM12/14/09
to clo...@googlegroups.com


2009/12/14 mbrodersen <morten.b...@gmail.com>

"an abuse of macros?"

HAHAHA you are funny Laurent :-)

?
 

lambdatronic

unread,
Dec 14, 2009, 12:45:27 PM12/14/09
to Clojure
Umm mbrodersen...I believe Laurent was merely pointing out that you
can accomplish everything you did with your macros with regular
functions. The functions are actually shorter and clearer to read
than the macros as well. That is a pretty clear abuse of macros.

The only thing macros do here is prevent you having to prepend ' or :
to your value or method names. IMHO (and I suspect I'm not alone on
this one) that's actually going to make your code harder to understand
than otherwise.

To demonstrate:

YOURS
=====

(defmacro ? [object value]
"Get an object value - same as object.value; in C# but immutable"
`(get ~object (keyword (str '~value))))

(defmacro ! [object method & args]
"Call an object method - same as object.method(args); in C# but
immutable"
`((get ~object (keyword (str '~method))) ~object ~@args))

(defmacro != [object name value]
"Set an object value - same as object.name = value; in C# but
immutable"
`(assoc ~object (keyword (str '~name)) ~value))

AS REGULAR FNs
==============

WITH QUOTED VALUES
==================
(defn ? [object value]
"Get an object value - same as object.value; in C# but immutable"
(object (keyword (str value))))

(defn ! [object method & args]
"Call an object method - same as object.method(args); in C# but
immutable"
(apply (object (keyword (str method))) object args))

(defn != [object name value]
"Set an object value - same as object.name = value; in C# but
immutable"
(assoc object (keyword (str name)) value))

WITH KEYWORD VALUES
===================
(defn ? [object value]
"Get an object value - same as object.value; in C# but immutable"
(object value))

(defn ! [object method & args]
"Call an object method - same as object.method(args); in C# but
immutable"
(apply (object method) object args))

(defn != [object name value]
"Set an object value - same as object.name = value; in C# but
immutable"
(assoc object name value))


And honestly, if you look at the keyword examples (the last 3
functions), it's hard to justify why you would even want to define
these functions in the first place.

1. (? object value) is longer and less idiomatic than (object value).

2. (! object method arg1 arg2 ...) is hardly shorter than
(apply (object method) arg1 arg2 ...), and the second one is again
idiomatic clojure and therefore easier for everyone to understand.

3. (!= object name value) just aliases != for assoc. Again, not
idiomatic.

So why exactly would you want to use these macros?

END OF LINE

Amit Rathore

unread,
Dec 20, 2009, 2:30:03 PM12/20/09
to Clojure
Just for kicks, I wrote a terribly simple implementation of an OO
system (with sub-type polymorphism).

Here's an example of it in use -
http://s-expressions.com/2009/12/10/frumios-a-silly-object-system-for-clojure/

Obviously one wouldn't use it in a real production system (one would
use multi-methods etc. instead), but it's fun to see that Clojure is
powerful enough to implement something like this in ~70 lines of code.
More importantly, it shows that if you use something like this OO
system which gives you most of what Java/C++ gives you in terms of
traditional OO, you're actually limiting yourself. Of course, you
could expand this into a full blown CLOS-style object system....

Reply all
Reply to author
Forward
0 new messages