Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Clojure(Script) reads Rubyish to me in the sense that I can't read the code until I understand every primitive. Contrast this with Python which almost reads like a natural language (which I don't say is better, but more explicit IMO).

    (defn widget-c [data owner]
      (reify
        om/InitState
        (init-state [_]
          {:message nil})
        om/IDidMount
        (did-mount [_]
          (let [events (sub (:notif-chan (om/get-shared owner)) :hello (chan))]
            (go
              (loop [e (<! events)]
                (om/set-state! owner :message (:data e))
                (recur (<! events)))))))
        om/IRenderState
        (render-state [_ {:keys [message]}]
          (if message
            (dom/p nil message)
            (dom/p nil "Waiting ... waiting ... waiting ..."))))


There is nothing implicit about that. You are instantiating an anonymous class (that's the reify) implementing 3 interfaces (presumably you looked these up since they're user libraries) that you are defining inline.

Compare this to something like a Django Rest Framework:

    class SnippetList(APIView):
        """
        List all snippets, or create a new snippet.
        """
        def get(self, request, format=None):
            snippets = Snippet.objects.all()
            serializer = SnippetSerializer(snippets, many=True)
            return Response(serializer.data)

        def post(self, request, format=None):
            serializer = SnippetSerializer(data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data, status=status.HTTP_201_CREATED)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
reify doesn't require any special knowledge that class doesn't. The Python code here is subclassing a single abstract class (APIView) instead of 3, but it has the same "problem" in that you have to know what methods to override. Again this is user code so you probably looked up what APIView needs to work just like you looked up with InitState, IDidMount, and IRenderState.

reify vs class in Clojure vs Python is a matter of idioms. You can definitely create an actual class instead of reifying in clojure, it just isn't necessary. Likewise, you could create an anonymous type in python via type(), but you'd probably get fired and/or shot in most circles for doing so.


I mostly wasn't talking about the high-level structure. Compare these methods:

        serializer = SnippetSerializer(data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data, status=status.HTTP_201_CREATED)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
with this:

        (let [events (sub (:notif-chan (om/get-shared owner)) :hello (chan))]
            (go
              (loop [e (<! events)]
                (om/set-state! owner :message (:data e))
                (recur (<! events)))))))
In order to have a remote idea what's going on, I need to know about channels, what `events`, `sub`, `go`, `loop`, `recur`, `<!` are. In Python, it's easy to tell syntax and primitives from library classes and methods, but here I'm not sure which is which. That's what I mean by Clojure being dense. Of course it's stupid to assume you read the source without understanding the language first, but “Python after you know some OOP“ is still easier to read for absolute language beginner than “Clojure if you know some FP”. Again, I don't imply that Python is somehow better because of that.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: