Conceptual difference between map and class

158 views
Skip to first unread message

Dieter Van Eessen

unread,
Mar 31, 2020, 4:41:02 AM3/31/20
to Clojure
Hello,

I've got a clojure and a python piece of code. Both seem to create what can be considered an instance of a class. Wherein lies the conceptual difference?

Python:
class MYCLASS():
    def __init__(self, x):
          self.x = x
    def MYMETHOD(self):
         ...

def MYFUNCTION():
    lol = MYCLASS()

Clojure:
(defn MYCLASS [x]
     {:x [x]
      :MYMETHOD (fn [] (MYCLASS ...))})

(let [lol (MYCLASS ...)])

I know its not valid code, but I hope you see what I'm aiming at: isn't using a map with functions in it just the same as a class?
Or is only the user interface of the language conceptually equal, while the underlying plumbing is completely different?
If this is the case, wherein lies the major differences?

If one could simply point me in the right direction, I'd already be very pleased. Most literature I've read so far only explains clojure can be used this way, but never focuses deeper on the subject.

kind regards,
Dieter

Jason Felice

unread,
Mar 31, 2020, 10:39:59 AM3/31/20
to clo...@googlegroups.com
A subtle difference between a map of functions and a Python class is that the class has implicit "self" or "this".  Otherwise, these are semantically the same.  Well, ignoring that Clojure maps are immutable.

In fact, C++ compilers compile methods by inserting a first "this" argument and mangling the name.  Virtual methods (ones which can be overridden) are collected into what is effectively a map attached to the instance.

--
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
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/clojure/49cd26ca-48ae-48b4-a5ab-b0f7c711b77e%40googlegroups.com.

Justin Smith

unread,
Mar 31, 2020, 1:12:14 PM3/31/20
to Clojure
I think it's also important here that Clojure methods are actual Java
methods - Clojure likes to stay close to the host functionality. A map
with a function isn't a class with a method because the JVM bytecode
doesn't let you invoke it that way directly. A Clojure function is not
a method because methods are not first class, it's an Object with a
static .invoke method (and some other details that are less important
here).

This object as hash with functions model is useful for learning (and
there's a lot of scheme and common lisp code that actually works this
way). With some effort, you can do everything with a function in a map
that you can with an object with a method if you are careful to
provide the object of the first arg.

But it's normal in Clojure to use the built in affordances. For real
code, defrecord gives you a new class that operates in a way similar
to this but with lower friction to the underlying bytecode (it
implements actual methods but also acts like a hash map for its
fields). Protocols let you use a hash map for extension (they act like
interfaces for classes, but you can add new implementations
dynamically, letting you do what you would do by adding a function
under a key on a hash, but tracking it on the protocol side).
> To view this discussion on the web visit https://groups.google.com/d/msgid/clojure/CAB6_SoYCTeKi2teO%3DbgyEB-Vu3C-fCGpX6T%3DXZB8ApmDP-c8vA%40mail.gmail.com.

Matching Socks

unread,
Mar 31, 2020, 6:24:35 PM3/31/20
to Clojure

James Gatannah

unread,
Apr 1, 2020, 12:44:07 AM4/1/20
to Clojure
It might be worth mentioning that, ultimately, python class instances are syntactical sugar built around an internal __dict__. It gets twistier, since classes are also instances of the base class object.

It would be tricky (though I've seen an example...maybe in Joy of Clojure? I think the author's conclusion was that it was an interesting experiment, but not worth doing in practice) to implement inheritance using clojure maps.

For me, the conceptual difference has been that it's better to just write functions that work on simple data structures, rather than tying a few together into a unit that only work on a single data structure (plus its derived classes). Clojure's emphasis on functional purity is another major piece of this puzzle.

Unit testing is one thing that becomes much easier with this approach.

I deal with a ton of python code that has tests built around dozens of mock objects mimicking things like database records from an ORM. And then we mock out a few low-level HTTP calls in base classes so the class instances we're trying to test in isolation don't break when we run the tests with no web server to call. Then someone refactors the code, and all the tests break because they're tied to a specific package/module structure.

By contrast, if you have your business logic in one set of pure functions, and you keep your side-effecting parts well isolated on the fringes of your system, you don't need any of that. Just call the business logic function with appropriate values and double-check the results.

You absolutely can write python code that way. But your pythonic colleagues will hate you for it.

Hope that helps,
James

Johannes

unread,
Apr 1, 2020, 2:44:00 PM4/1/20
to Clojure
A few years ago I built some kind of internal DSL using Clojure macros which allowed to create objects and classes like in conventional OOP languages as Smalltalk and Java.

The macro obj creates a classless, immutable object, for example:
(obj {:x 1, :y 2} {:f (fn [] (+ (self :x) (self :y)))})
obj expects to maps as arguments, one for the instance variables (:x and :y) and one for the methods (:f). The variable self is provided by obj automatically.
The methods can be activated using a message passing style:
((obj {:x 1, :y 2} {:f (fn [] (+ (self :x) (self :y)))}) :f) ;=>3
Classes can be created through an explicit abstraction step by sending the message :kappa to an object:
((obj {:x 1, :y 2} {:f (fn [] (+ (self :x) (self :y)))}) :kappa 'C) ;=> #'dosl2clj.core/C
Classes understand the message :new  for creating new instances:
((C :new) :data) ;=> {:x 1, :y 2}
All objects understand the message :data. Class hierarchies are possible, too.

I built the DSL, because I wanted to figure out, wether it could make porting an application from Smalltalk to Clojure less difficult. I tried two simple applications.
My conclusion is: Yes, the porting is possible, of course, and quite simple. But it is in no way simpler than using the native Clojure language features. Using normal hash-maps and functions isn't more difficult. Building a DSL for objects isn't worth the effort.

Johannes

Dieter Van Eessen

unread,
Apr 2, 2020, 2:43:04 PM4/2/20
to Clojure
Thanks alot for all the answers,
still getting my head around the matter :)

Dieter Van Eessen

unread,
Apr 4, 2020, 1:24:17 AM4/4/20
to Clojure
Thanks, I'm currently reading the book you mentioned (Joy of Clojure). Just started on 'Types, protocols and records'...
Still doubting if I should continue learning clojure. From my point of view, the only major advantages of the language so far, are 'clojurescript' and the idea that I can evaluate stuff that I've 'printed' (data is code is data).
Other than that, they are messing with my head by redefining existing abstraction and making them 'almost equal but slightly different'.

kind regards,
Dieter

Brandon R

unread,
Apr 4, 2020, 2:42:31 PM4/4/20
to clo...@googlegroups.com
I think someone else here could give a more detailed answer, and I will just give it from my point of view. What I really like about Clojure, coming from C# and JavaScript (and toying with other languages), is the immutability, the concurrency features, the state management features, and the concision of the language. These benefits become better understood with time of usage, but I can say that in my experience, the code that I write in Clojure is much more bug-free, much more concise, and much easier to understand (there is way less code to reason about).

If you haven't watched Rich Hickey talks, I recommend Are We There Yet? and Simple Made Easy. These talks really helped change my perspective on, at least, imperative / OOP oriented languages. among other things.




--
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
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.

Ernesto Garcia

unread,
Apr 5, 2020, 5:03:30 AM4/5/20
to Clojure
In my humble opinion, main benefits of Clojure:

- Development cycle: modifying and experimenting on a running program.

- Treating data as maps. Direct and efficient immutability.

- Macros: Though used very scarcely, it's good to know that you'll be able to extend the language from within if you need to.


> redefining existing abstraction and making them 'almost equal but slightly different'.

What do you mean here? Clojure, and practical languages in general, do not define new ways, they usually select what is considered more appropriate.

James Gatannah

unread,
Apr 5, 2020, 5:26:44 AM4/5/20
to clo...@googlegroups.com
"A language that doesn't affect the way you think about programming is
not worth knowing." - Alan Perlis

A lot clojure's culture and philosophy is centered around Rich's talks.

I resisted this for a very long time. I'd rather spend 10 hours
reading a book than 1 hour watching someone speak. I was wrong.

Joy of Clojure is really a...well, maybe not an "advanced" clojure
book. But it also definitely isn't a beginner's introduction.

I've gotten rave reviews from very senior programmers about "Clojure
for the Brave and True." Its whimsical style isn't for people who just
want to dive into the nuts and bolts, but those people are almost
definitely going to miss the bigger picture.

Personally, I wound up loving clojure from the perspective of a python
programmer. I got to python from c++ because I got fed up with all the
stupid boiler plate code and time I wasted waiting on the compiler.

From there, I ran across enough people raving about common lisp to
convince me to read http://www.gigamonkeys.com/book/

I spent a couple of years trying to do anything worthwhile with common
lisp in my spare time.

I kept hitting limitations in the C library layers. x can't work in
64-bit Windows. Y cannot compile on Thursdays. That sort of thing.

I really, really wanted to turn that into my goto, every day,
"my-time" programming language.

And I just couldn't.

The support base of people who are using it just is not broad enough.

This is why clojure's decision to embrace the "hosted platform" thing
is brilliant. Clojure on the JVM has access to anything that java can
get to. ClojureScript has the potential to be even broader, since
javascript.

I still treasure fantasies of going back to common lisp. But, really,
clojure has a better answer to a lot of modern computing problems.

When I ran across clojure for the first time (because people I
respected convinced me to look at it, even though I thought I knew
that common lisp must be better), I hated it. This was way before
lein, so you had to deal with all the baseline java stupidity to build
your CLASSPATH. And the way it manages state seemed idiotic. I was a
seasoned C programmer who thought I knew how to handle all the issues
that came with multi-threading.

I was wrong.

It gets more complicated. Things like AWS lambdas push back on the
problems that clojure solves.

In a lot of ways, they force you to do the same things that clojure
does naturally, because they're stateless. And they're a poor fit for
clojure because its startup time still isn't great.

This is all me rambling. I'm sorry.

Is clojure a good language for you to learn now?

Well, that depends on where you are and what you already know.

I work with a bunch of people who went through the same programming
101 course. It forced them to learn things like Haskell and Clojure,
because the professor is a technical programming weanie.

I feel sad for these people and have to fight against them constantly
because there is no way for them to appreciate what you get from a
functional programming paradigm until you've dug the trenches and seen
1st-hand just how awful the alternatives are.

I don't know where you are in your life/career, so I don't have any
justification for offering this opinion. I'm going to anyway.

I think that may be the litmus test for your question: have you hit
the point where you think "there must be a better way to do this?"

It never hurts to learn a new language. That's always a good idea.
But, if you're still content with what you can do with python, then I
advise you to keep working in python. Just keep clojure in mind the
next time you hit an "OMFG! How did this bug escape into production?!"
moment.

It isn't a trivial transition. But it's almost guaranteed that
translating your web server from python to clojure will make it more
stable.

Clojurescript is awesome, but (in this scenario), it's also just icing.
> --
> 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
> ---
> You received this message because you are subscribed to a topic in the Google Groups "Clojure" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojure/qkepFF4qtbY/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to clojure+u...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages