Fork me on GitHub
#clojure
<
2022-03-11
>
Victor Mataré14:03:22

Hey... design/philosophical question here: Say you have an application-specific data structure T with special identity semantics. That is, it has some field x in T that is irrelevant to its identity, so (= a b) for a, b instanceof T should disregard the values of x in a and b. If I'm reading https://clojure.org/guides/equality correctly, the only way to achieve that is with deftype or by actually writing a java class. So far so good. But what if I need that structure to support clojure's map semantics? I.e. I want to be able to access the fields via keywords and be able to do things like (:x a) and so on. Then deftype is out of the question because it can't extend classes, only implement interfaces. So the only remaining option would be some java class along the lines of public class T extends clojure.lang.PersistentHashMap { ... }. But would that actually work transparently in all cases? I have a feeling there might be weird implications that let it break down in certain contexts. Also, https://clojure.org/reference/datatypes#_why_have_both_deftype_and_defrecord tries to make a rather nebulous argument as to why I wouldn't even want application-specific datatype semantics in general. But custom identity semantics is a thing and if you're dealing with complex data structures it may be an essential tool to achieve proper encapsulation and separation of concerns. Is there some other way I'm overlooking here?

p-himik14:03:17

> Then deftype is out of the question because it can't extend classes, only implement interfaces But you can extend all the right interfaces to introduce map semantics. There's no real need for inheriting classes here. In fact, it's actually better if your fields are proper members of T. If I'm not mistaken, that's exactly how records achieve map semantics.

Victor Mataré14:03:31

So you're saying I should basically re-implement clojure.lang.PersistentHashMap? Sure I could, but that'd be pretty much the opposite of sustainable software engineering.

Alex Miller (Clojure team)14:03:58

typically in this case you would implement IPersistentMap, not extend PHM

Alex Miller (Clojure team)14:03:14

and you can, for example, hold a map as a field and defer most calls to that

Victor Mataré14:03:05

yeah, delegating to PHM would certainly be better, but still it increases the maintenance burden if e.g. clojure's relevant interfaces & implementations change.

msolli14:03:53

Not likely that it would, given its history and Clojure’s commitment to not breaking existing things: https://github.com/clojure/clojure/commits/master/src/jvm/clojure/lang/PersistentHashMap.java

1
Sam Ritchie14:03:11

This sounds like a great use case for metadata

Alex Miller (Clojure team)14:03:25

metadata is defined with the caveat that it doesn't affect equality, so seems like a terrible use case for that

Sam Ritchie14:03:38

“terrible”, yikes. Or maybe I simply misread the comment after > That is, it has some field x in T that is irrelevant to its identity, so (= a b) for a, b instanceof T should disregard the values of x in a and b. If I’m reading and didn’t see that he wants :x to work as an accessor etc

Alex Miller (Clojure team)14:03:58

making this easy is a non-goal - you are strongly encouraged to use the built-in collection types and value equality semantics. if you want something else, that's possible but the burden is on you. there are some libraries like Potemkin that have helpers for creating custom map-like structures

Victor Mataré15:03:47

> making this easy is a non-goal - you are strongly encouraged to use the built-in collection types and value equality semantics. if you want something else, that's possible but the burden is on you. Yup, that was my vague impression as well: It's just not a design goal of the language, also due to its heritage. But I'll definitely take a look at potemkin, thanks for the pointer 👍

Joshua Suskalo15:03:01

@U02PSA71D0E what about metadata? You can store fields that don't contribute to equality semantics in the metadata map, and most operations preserve metadata.

🙌 1
Joshua Suskalo15:03:13

It may not work for you, but it may be easier than implementing your own persistent map

Joshua Suskalo15:03:00

I see that suggestion was already discussed.

Victor Mataré15:03:22

Hm... making the "irrelevant" fields metadata so they don't contribute to the map's identity... @U064X3EF3 said it's a bad idea, but maybe he interpreted the suggestion differently...? The way you put it, it definitely sounds very interesting.

Alex Miller (Clojure team)15:03:50

yeah, if you are just "adding" non-data then metadata is a good use case for that

Alex Miller (Clojure team)15:03:12

maybe I was too into the original description

Victor Mataré15:03:34

That sounds very much like the "other way" I was overlooking 😁

wevrem00:03:28

Hey @U02PSA71D0E , it seems maybe you’ve got your answer for “how”. But I’m curious about the “why”. What kind of structure do you have where equality needs to ignore a field? Could that be modeled as two separate entities? Like you have a and b, and others like them stashed somewhere, and then some other structure holds a map of a to a’s value for :x, and b mapped to b’s value of :x . I’m trying to imagine the scenario you’ve described. More details, please.

walterl00:03:04

I'd rather write a separate T= function, so as not to break existing language semantics. I.e. Don't make equality checks pass, because they're not equal. Rather introduce the new notion of equality, separately.

☝️ 1
njj14:03:10

Does anyone know of a interactive online Clojure repl that allows to load dependencies? I generally use http://repl.it but it seems I can’t load any external libs. I’m looking for something to use for technical interviews

p-himik14:03:26

Maybe https://github.com/PEZ/pirate-lang can be useful here. Although I'm not sure why the REPL functionality has to be online for a technical interview.

👍 1
Alex Miller (Clojure team)16:03:48

One more chance to complete the 2022 Clojure Survey!! https://www.surveymonkey.com/r/clojure2022

clojure-spin 3
👀 1
Eddie16:03:48

I am working on an JVM instrumentation library for Clojure which works with Java 9 and up. It doesn't work with Java 8 because it depends on modules that on were only available in tools.jar prior to Java 9. I just found out my motivating use case has a critical dependency that only supports Java 8. I'm kicking myself for not checking this sooner. Does anyone know of work arounds for detecting the location of tools.jar in Java 8 and programmatically adding it to the classpath?

Cam Saul16:03:07

It should be in $JAVA_HOME/lib

👍 1
ghadi16:03:08

what are you grabbing from tools.jar?

Eddie17:03:50

I need com.sun.tools.attach.VirtualMachine and maybe a couple of other things I haven't discovered yet.

neupsh17:03:17

Last time I looked into it, it was available in <jdk home>/lib directory (not jre).

Eddie17:03:35

Thanks @U42REFCKA and @U3MRWH35M. It looks like URLClassLoader will do the trick if the jar can be found at that location, right?

neupsh17:03:56

One issue I ran into was that the jdk version for tools.jar had to match the jre version it is running for, IIRC.

jumar17:03:14

It would be interesting to hear what exactly are you doing with the tool/library. Perhaps there are existing tools that can solve your problem immediately?

1
Eddie17:03:09

I am attaching an instrumentation agent to the current JVM process. Essentially the same thing done for the "ouroboros" agent of https://github.com/HCADatalab/powderkeg. (https://www.youtube.com/watch?v=OxUHgP4Ox5Q) Then I am using the agent to write class files for all of the in-memory classes created by the Clojure compiler at runtime. The purpose is for distributing work to a remote JVM.

vemv11:03:05

https://github.com/pallet/lein-jdk-tools does exactly this https://github.com/clojure-emacs/enrich-classpath also does it, but also does quite a lot more :) so could be only serve as inspiration (I don't remember if there's any substantial difference between most impls. Most likely not)