Fork me on GitHub
#clojure
<
2023-06-24
>
Aquati02:06:50

Folks, in Java we can extend a class and obtain all methods and implementations of the class, including from other classes they extended, overriding methods and having the ability to call the original methods via a call from super*.*

class A {
    public void hello() {
        System.out.println("Hello");
    }
}

class EvilA extends A {

    @Override
    public void hello() {
        System.out.println("I am evil!!");
        super.hello();
    }
}
Can we achieve something similar with Clojure using defprotocols and defrecords? I am curious if we can extend a defrecord that implements some defprotocols, override some implementations and still having access to the originals "methods" like we can with super

hiredman03:06:24

In general, don't use defrecords, use maps

hiredman03:06:49

Don't use methods/protocols/multimethods/etc use functions

hiredman03:06:16

(defn hello [m] (println (:name m)))

hiredman03:06:53

Works on any map with a :name key without any kind of silly instance of relationship between the maps

Aquati03:06:48

Yeah, I agree, I just wanted to understand the limitations of defrecord/defprotocol comparing to Java classes. Like, if I could modify a defrecord from a external library that I don't control to modify some behavior of the implementation. This is a hypothetical 😛 I know probably this isn't a good idea to mess up with code you aren't supposed to access, but its just some hypothetical thing that I was wondering if was possible to achieve in Clojure like it is in Java

Aquati03:06:32

In Java, for example, I could extend some credential provider from AWS SDK to fetch credentials with an unique crazy way that I would want to just by overriding some methods. Sounds like a bad idea too, but it's possible. This thought made me wonder if defrecords are capable of something like that too. But you already clarified that isn't possible for me, thanks 🙂

jamesleonis04:06:42

I think I understand what you are trying. In Java/C++/etc you can build class hierarchies and reference functions from parents. Library consumers can inherit from library classes to extend functionality. In Clojure, Multimethod + Hierarchies feature might give you the tools to build something similar by allowing you to define arbitrary hierarchies and dispatch on them. https://clojure.org/reference/multimethods

hifumi12304:06:57

> Like, if I could modify a defrecord from a external library that I don’t control to modify some behavior of the implementation. I dont think so. I would only attempt “overriding” behavior with multimethods.

hifumi12304:06:50

if you want some notion of inheritance or dispatching, multimethods are designed exactly for this

potetm10:06:37

You can do this in clojure with proxy fyi

potetm10:06:23

Just not records.

phill13:06:39

An initial Clojure developer once commented, "there is no dishonor" in stepping back to the host language. Implementation inheritance is evil, and you can have it if you want it, so I don't consider this a "limitation" of Clojure, more like a central tenet.

Dallas Surewood13:06:05

Does anyone have experience with and would recommend lambdaisland?

oxalorg (Mitesh)13:06:35

Hey @U042LKM3WCW we’ve made lambdaisland completely free, you can access our episodes here: https://lambdaisland.com/episodes Sorry the payment pages are still up so maybe that’s leading to some confusion!

Dallas Surewood13:06:54

Oh wow, thank you!

💚 2
oxalorg (Mitesh)13:06:44

Feel free to ping me if you have any other queries bowtie

🙌 2
Dallas Surewood18:06:03

I'm trying to setup logging for clojure/tools.logging and I'm noticing this package recommended in a lot of places ch.qos.logback/logback-classic It's not in clojars though. Has this been taken down?

seancorfield18:06:51

Non-Clojure dependencies are on Maven Central, not Clojars.

seancorfield18:06:09

(Clojure itself and all the Contrib libraries are also on Maven Central, rather than Clojars)

Dallas Surewood18:06:32

So what is Clojars in that sense? Just a place that points to the other repos?

seancorfield18:06:01

Clojars is a community Maven-style repo created for and managed by the Clojure community for easier publishing of artifacts.

seancorfield18:06:40

Maven has stricter requirements for publishing artifacts (stricter group ID rules, stricter signing rules, etc).

Dallas Surewood18:06:14

So when I put this in my deps.edn ch.qos.logback/logback-classic {:mvn/version "1.4.8"} Is that only ever gonna fetch from Clojars, or does it go to Maven directly?

seancorfield18:06:59

It's also worth noting that Maven-style repos are usually considered "immutable" in that published artifacts never go away. Or "append-only" insofar as only new artifacts are added -- all existing artifacts are untouched.

seancorfield18:06:25

tools.deps -- just like the machinery behind Leiningen -- always searches Maven Central first, then Clojars.

p-himik18:06:28

That's not the case with snapshots, is it? The append-only bit.

🎯 2
seancorfield18:06:41

Yes, all snapshots remain available.

seancorfield18:06:10

The name is symbolic and resolves to the latest date/time stamp but you can still reference older snapshots by their specific date/time stamp.

p-himik18:06:16

I mean, the author can overwrite any snapshot easily, no?

seancorfield18:06:56

You can "append" a new snapshot, and the symbolic name will refer to that (like the unsupported RELEASE and LATEST symbolic names, in a way).

p-himik18:06:32

Ahh, gotcha. Didn't know you can point at things with dates.

seancorfield18:06:11

And here's the symbolic name in action, followed by a specific date/time stamp version:

(~/clojure/play)-(!2024)-> clj -Sdeps '{:deps {com.github.seancorfield/honeysql {:mvn/version "2.4.9999-SNAPSHOT"}}}'
Downloading: com/github/seancorfield/honeysql/2.4.9999-SNAPSHOT/maven-metadata.xml from clojars
Downloading: com/github/seancorfield/honeysql/2.4.9999-SNAPSHOT/honeysql-2.4.9999-20230624.172615-34.pom from clojars
Downloading: com/github/seancorfield/honeysql/2.4.9999-SNAPSHOT/honeysql-2.4.9999-20230624.172615-34.jar from clojars
Clojure 1.11.1
user=>

Sat Jun 24 11:35:12
(~/clojure/play)-(!2025)-> clj -Sdeps '{:deps {com.github.seancorfield/honeysql {:mvn/version "2.4.9999-20230624.172615-34"}}}'
Clojure 1.11.1
user=>

seancorfield18:06:13

Or an older snapshot:

(~/clojure/play)-(!2026)-> clj -Sdeps '{:deps {com.github.seancorfield/honeysql {:mvn/version "2.4.9999-20230623.230951-33"}}}'
Downloading: com/github/seancorfield/honeysql/2.4.9999-SNAPSHOT/honeysql-2.4.9999-20230623.230951-33.pom from clojars
Downloading: com/github/seancorfield/honeysql/2.4.9999-SNAPSHOT/honeysql-2.4.9999-20230623.230951-33.jar from clojars
Clojure 1.11.1
user=>

p-himik18:06:23

Sweet, thanks!

Dallas Surewood18:06:02

Sean, what's your approach to handling "something went wrong unexpectedly, let's recreate the situation." I've been doing my best to keep everything as functional as possible, but I feel like when a request goes bad that shouldn't because I have nil somewhere, for example, it's still hard to trace down. Do you just put taps in the function and try to do the same browser clicks that made it happen? Or do you have logging setup so you know exactly what call with what arguments made that happen?

seancorfield19:06:36

It depends on the situation. When you get an exception, the stacktrace provides a bread crumb to where it failed. But why it failed is going to depend on the specific code that failed.

seancorfield19:06:23

(sorry, brunch interrupted)

seancorfield19:06:10

Some of the ability to debug just comes with time and familiarity with Clojure, some of it is really about taking an analytical approach -- Stu Halloway's https://www.youtube.com/watch?v=FihU5JxmnBg is a good watch for tips on that. https://www.youtube.com/watch?v=OUZZKtypink is another good one. Transcripts if you prefer to read: https://github.com/matthiasn/talk-transcripts/tree/master/Halloway_Stuart

seancorfield20:06:49

Going back to your OP question, we use logging for a number of things at work but mostly logging goes in and stays in -- we have all our logging going to New Relic where we can run queries against WARN and ERROR level stuff (we drop INFO and below there). We have everything go into rolling log files on the servers too -- including INFO level and DEBUG from our own code -- and we also have a colorized console log that has just WARN/ERROR and that goes into a non-rolling file. We also try to add quite a bit of context to logging -- via MDC -- so all log messages include user ID, IP, and some other information as available. That allows us to query via user ID or IP etc in New Relic and see all WARN/ERROR in the UI -- or we can grep in the rolling log files for DEBUG/INFO if we need more information. When developing locally, I also have all clojure.tools.logging wired into tap> so that all shows up in one of my Portal windows (in VS Code) -- as well as rolling files and console log locally 🙂 And then I can add tap> calls as needed for debugging (or while doing exploratory development) and those go into a separate Portal window (also in VS Code).