Fork me on GitHub

@cfleming: I have an external tool similar to the IntelliJ Todo "applet" -- it collects comments matching a certain regex, and when you click on the comment, it jumps the IDE to the corresponding file/line

Kari Marttila10:11:24

Clojure gurus! I'd like to have a short comment to one design decision. I have three various environments which all connect to their data sources a bit differently and also the data processing is a bit different. I need to implement n different functions for data processing. I could do this using multimethods and dispatch based on environmental variable value which I know for each environment (defined in profiles.clj). But I was wondering if this could be implemented more elegantly e.g. using protocols. Any suggestions?

Kari Marttila10:11:46

I was reading about protocols in "Joy of Clojure" and "Clojure Applied". I think I have an idea how to do it more elegantly. I create one namespace per one environment/defrecord definition, and inside that defrecord I define the data processing functions for that environment. I'll create a git branch for this and experiment a bit. Clojure is so fun. ๐Ÿ™‚

metal 4
Kari Marttila13:11:48

Damn, I love Clojure REPL. And using IntelliJ IDEA with Cursive and its REPL makes experimenting with the code so fluent and fast. I was having major difficulties to figure out how to call function b from function a using the same protocol. Then I experimented it using REPL and figured out how to do it in a couple of minutes just by experimenting.

โค๏ธ 4
๐ŸŽฉ 4

"You're living in your program invoking your tools, instead of living in your tools invoking your program" - Stuart Halloway.

๐Ÿ‘ 4
Kari Marttila13:11:12

But... I have one issue I can't figure out how to do and the Clojure books I have doesn't provide an example for that.


And what would that be?

Kari Marttila13:11:59

(defprotocol EmailProtocol (lowername [this name]) (email [this host])) (defrecord EmailRecord [ourcompany] EmailProtocol (lowername [this name] (clojure.string/lower-case name)) (email [this contractor] (let [contractorname (lowername this contractor) companyname (lowername this ourcompany)] (str "ext-" contractorname "@" companyname))))

Kari Marttila13:11:21

This works well when EmailProtocol and EmailRecord are in the same namespace...

Kari Marttila13:11:21

But if I put EmailRecord into another namespace then Clojure complains that it cannot find function lowercase...

Kari Marttila13:11:57

(def ourcompany (->EmailRecord "CoolCompany")) (lowername ourcompany "David") => "david" (email ourcompany "David") => "[email protected]"

Kari Marttila13:11:50

So, if defrecord EmailRecord is defined in another namespace, the Clojure complains that: Unable to resolve symbol: lowername in this context


Please evaluate the following forms in your repl.


(ns pro)
(defprotocol EmailProtocol
 (lowername [this name])
 (email [this host]))
(ns user)
(require '[pro])
(defrecord EmailRecord [ourcompany]
  (lowername [this name] (clojure.string/lower-case name))
  (email [this contractor]
    (let [contractorname (pro/lowername this contractor)
          companyname (pro/lowername this ourcompany)]
      (str "ext-" contractorname "@" companyname))))
(def ourcompany (->EmailRecord "CoolCompany"))
(pro/lowername ourcompany "David")
(pro/email ourcompany "David")


You wanna require and namespace qualify the protocol.

Kari Marttila13:11:17

Damn, that worked. Why didn't I figure that out. ๐Ÿ™‚


I defined the protocol (abstraction) in the namespace pro and depend on (`require`) the abstraction in the implementation, the user namespace.


In fact, the definition of the protocol, the record/type, and the coupling of the protocol and the implementation can be in three different namespaces.


This means you can extend a third party type to a protocol by yet another third party in your namespace.

Kari Marttila14:11:33

Ok. Good to know. I'm just learning how to use protocols...

๐Ÿ‘ 4
Kari Marttila14:11:48

They seem to be very powerful abstraction.


This is Clojure's solution to the expression problem.


who needs types anyway


everything is a pixel type ๐Ÿ˜›


(seq my-sorted-map) will always return entries in order?


Hi, how can I append into an atom?


(def tv-state {:tales [{m1} {m2} {m3}]})


I want to (swap! tv-state ??? [:tales] m4)


to get tv-state {:tales [{m1} {m2} {m3} {m4}]}


? did you delete your solution? it worked haha

Marc O'Morain21:11:42

I wanted to test in a repl ๐Ÿ˜„


XD i just tried it and it works perfectly

Marc O'Morain21:11:18

(swap! tv-state update :tales conj m4)


(swap! tv-state update :tiles conj new-post-map)

Marc O'Morain21:11:02

I took me a mental leap to understand that the first time.

Marc O'Morain21:11:25

You are calling update on the the value of tv-state

Marc O'Morain21:11:42

and you are passing conj new-post-map as the arguments to update


i kept putting [:tiles] instead of just :tiles


so many tabs in search of the answer... so thanks ๐Ÿ˜„


how do I ignore a variable when unifying in core.logic? the usual suspect of _ fails in this case: (== x [_ b])


Do you have a larger example?


not sure if this is what youโ€™re looking for, but you could introduce a new, unbound logic variable in that position: (== x [(lvar) b])


@sova If you use update-in, you can pass [:tiles] -- just in case you want to go deeper into a nested structure and need multiple levels.