clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
rutledgepaulv 2021-01-01T06:01:24.221Z

it sort of depends on the class. if there's an interface for it you can use java proxies to maintain the interface while adding additional stuff.

rutledgepaulv 2021-01-01T06:01:42.221200Z

or if you can do a delegate pattern

rutledgepaulv 2021-01-01T06:03:10.221400Z

delegate example to add metadata to an InputStream: https://github.com/RutledgePaulV/kube-api/blob/master/kube-api-core/src/kube_api/core/http.clj#L10-L25

Ivan Fedorov 2021-01-01T07:45:29.223Z

Fellow clojurians, can anyone run this snippet

(let [zdt (ZonedDateTime/of (LocalDateTime/of 2020 12 31 0 0) (ZoneId/of "America/New_York"))
      f (DateTimeFormatter/ofPattern "YYYY-MM-dd")]
  (.format zdt f))
and say what it outputs? I’m getting “2021-12-31” on JDK10 and 11 for some reason UPDATE: ok, solved. It’s just my formatting mistake. – Y is for week-based-year – y is for era year So yyyy and all works

borkdude 2021-01-01T11:59:01.224300Z

Please add the imports for anyone too lazy to figure those out

Louis Kottmann 2021-01-01T14:23:31.226600Z

Hello, after working on bots in ruby, for the past few months I've been working on a Slack bot in clojure, using the latest Slack events API & interaction API, clojure's async capabilities and other good stuff it provides help and command completion via back-and-forth with users for prompting values in the form of buttons/datepickers/etc. It allows you to define steps to generate an output with pedestal-backed interceptors. Registering a command looks like this:

Louis Kottmann 2021-01-01T14:23:51.226900Z

A more complex command looks like this (with parameters and prompting):

Louis Kottmann 2021-01-01T14:23:57.227300Z

I'm wondering now if it could be useful to others, and if I should try and release a library out of it Mind you, I'm new to Clojure and the code is probably not idiomatic, I could use some help in the process

2021-01-01T15:52:51.230300Z

Anyone have any luck installing Clojure CLI tools via HomeBrew on an Apple Silicon machine? Fails for me when trying to build an aarch64 OpenJDK. I’d like it to skip that step, but didn’t have any luck telling it to just ignore the dep (it goes looking for it even though it didn’t pull it in as a dep).

GGfpc 2021-01-01T18:10:25.232300Z

Is there a way to redefine a function that is called inside the function I want to test? Say function A calls B which calls an external API. I want to override B to return something so I can test A without having to call the API

2021-01-01T18:11:10.232900Z

the best choice is to parameterize, second best is to not use any threads and use with-redefs

2021-01-01T18:12:08.233700Z

parameterizing could mean taking an implementation of some protocol as an argument, and using a test-implementation in your test, or just taking a function to call as part of the argument list

2021-01-01T18:12:37.234300Z

this combines nicely with things like stuartsierra/component or integrant that do state management as well

2021-01-01T18:13:05.234800Z

(nb I mention not using threads explicitly because with-redefs is not thread safe)

GGfpc 2021-01-01T18:13:42.235Z

Thanks!

2021-01-01T18:14:37.235600Z

there's also the in-between choice of using a dynamic var plus binding to override - at least that's thread safe

alexmiller 2021-01-01T18:24:36.236400Z

Did you use the Clojure tap?

alexmiller 2021-01-01T18:26:16.237900Z

brew install clojure/tools/clojure` Or brew install clojure

alexmiller 2021-01-01T18:27:29.239500Z

Those formulas declare java as a dep differently, not actually sure either will work

simongray 2021-01-01T18:48:07.244300Z

Where does it make the most sense to put your protocol definitions, supposing you have lots of them? You can put them all in a core namespace, but doesn’t this complect the core namespace? You can put them in lots of separate namespaces according to a separation of needs, but doesn’t this obfuscate their existence somewhat? And won’t it potentially result in many unclear requires?

clyfe 2021-01-01T18:51:14.244600Z

Lots of separate namespaces according to a separation of needs; and these be in the private api; separate public api with plain functions that calls into them. Or so the mailing list says... https://groups.google.com/g/clojure/c/YwhOGCWquIM/m/bLC1YYGxe8MJ

2021-01-01T18:55:13.244800Z

this is part of why I hate the name "core" - the top level ns shouldn't contain the protocol definitions as they belong at the bottom of the require tree, and the top level ns belongs... at the top

👍 1
2021-01-01T18:56:19.245Z

then the top level definitions combine implementations of the protocols with functions calling protocol methods

2021-01-01T18:57:08.245200Z

there are plenty of clojure devs who avoid private definition, that's an implementation detail here

2021-01-01T19:28:57.249300Z

I’ve always wondered about that, too. I always put them in a separate namespace, so the implementation namespaces can require them, and the core api has functions calling the protocol methods, and requires the implementation namespaces so they get compiled. But is there an easier way?

vemv 2021-01-01T21:06:37.249700Z

I'd say that simply sharing it cannot hurt! there's nothing wrong with a tentative or 'playground' repo you might find specific help or perhaps some a kind code review over #pedestal

vemv 2021-01-01T21:25:19.251200Z

I need a few more large, java-heavy oss clj projects to try a certain tool on. e.g. Crux, Metabase. suggestions? :)

2021-01-01T21:38:14.251300Z

Not sure if they're java-heavy enough but: https://github.com/pallet/pallet (for an old one) https://github.com/riemann/riemann

🍻 1
vemv 2021-01-01T21:42:23.251700Z

bet they are transitively java-heavy at the very least ;p thanks!

👍 2
Mike Martin 2021-01-01T21:52:41.255Z

hello! 👋 Can anyone help me understand why this code works the way it does?

(get 5 :foo) ; => nil
The documentation for get indicates that a map should be provided, but if you provide any non-map data structure it still works without throwing an exception. I attempted to look at the source for get but found that its definition was seemingly recursive and somehow bottoms out in clojure.lang.RT.

Mike Martin 2021-01-01T21:55:16.255100Z

a little more poking around in clojure.lang.RT yielded this section which I believe contains the answer I’m looking for https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L758-L793

Mike Martin 2021-01-01T21:55:31.255400Z

so uh.. thanks for letting me rubber duck in here 😅

2021-01-01T21:58:20.255600Z

as that code shows, it works with anything that is ILookup, but also anything getFrom can handle

2021-01-01T21:58:50.255800Z

so it works on built in types clojure doesn't redefine:

)user=> (get "hello" 1)
\e

dorab 2021-01-01T21:59:02.256Z

One caution (that @noisesmith refers to) is to never directly expose a protocol to the outside world. Do it via a function that then calls the protocol method. That way, you can change the protocol without impacting external callers. This way also helps if you need to later add any pre- or post-processing. If the protocol is only ever used internally, by namespaces you control, then the above is not needed.

2021-01-01T21:59:08.256200Z

it turns out that getFrom is quite permissive and returns nil instead of erroring on absurd input

2021-01-01T21:59:40.256400Z

a silly consequence of this is that any usage of get can be replaced with (get get get get) (even recursively, of course)

Mike Martin 2021-01-01T22:02:24.256600Z

thank you for the additional detail! Normally I never would have tried to feed get non-map input but the example in chapter 5 of clojure for the brave and true incidentally processes a map where an integer gets fed into get and I was really surprised that it just worked

2021-01-01T22:03:58.256800Z

yeah, it can be the source of strange deeper bugs

2021-01-01T22:04:21.257Z

see for example

user=> (get (atom {:a 0}) :a)
nil
oops! forgot to deref

😫 1
Mike Martin 2021-01-01T22:06:37.257300Z

yikes that would be a pain to debug. Any idea what the rationale is for get returning nil instead of throwing an exception? I suppose it’s better to be permissive so that dynamic usage of get doesn’t blow up in the wild maybe?

seancorfield 2021-01-01T22:14:44.257500Z

We've talked about writing this up to add it to the FAQ on http://clojure.org since it seems to trip every new Clojure developer up at least once, and there isn't currently a single place we can point folks to, by way of explanation.

seancorfield 2021-01-01T22:17:36.257700Z

Part of it is consistency: you can always call get on something without an exception -- you just get nil back if the "key" isn't found in the "collection". (get {:a 1} :b) returns nil, (get {:a 1} :b :c) returns :c (the "not found" arity). This is consistent with (coll :b) returning nil and (coll :b :c) returning :c -- since some collections can act as functions and look their argument up in themselves -- and also with (:b coll) and (:b coll :c) which is because keywords can also act as functions and look themselves up in their argument.

seancorfield 2021-01-01T22:19:40.257900Z

Returning nil for "not found" (or the supplied "not found" value) means that you can omit a lot of special case checking and validation on the "coll" argument in all of this and know that if you get non-`nil` (or you don't get the "not found" value) then the "coll" does indeed contain the key and your code can continue. All other cases just reduce to nil-punning without needing exception handling.

seancorfield 2021-01-01T22:20:42.258100Z

If you want an exception for non-collection arguments, you can check for the presence of the key with contains? first: (contains? 5 :foo) throws an exception.

❤️ 1
seancorfield 2021-01-01T22:22:13.258300Z

There's also nth -- compare against get behavior:

dev=> (get [1 2 3 4] 10)
nil
dev=> (nth [1 2 3 4] 10)
Execution error (IndexOutOfBoundsException) at dev/eval10311 (dev.clj:1).
null
dev=> (nth 5 10)
Execution error (UnsupportedOperationException) at dev/eval10315 (dev.clj:1).
nth not supported on this type: Long
dev=> 

❤️ 1
seancorfield 2021-01-01T22:22:44.258500Z

Is that helpful background/motivation @mike973?

Mike Martin 2021-01-01T22:26:59.258700Z

that is very helpful, thank you for taking the time to explain that. It’s also a good reminder that I should go and read up on nil-punning. I have a cursory understanding of it but this situation has certainly shed some more light on the topic

simongray 2021-01-01T22:45:58.258900Z

@dorab This is mostly about implementing the Datafy protocol for a bunch of different Java 0bjects.

simongray 2021-01-01T22:48:45.259300Z

^^ I wonder if you answers are still the same? @noisesmith @claudius.nicolae

2021-01-01T23:04:46.259600Z

in that case you aren't defining any new protocols, right?

simongray 2021-01-01T23:37:38.260200Z

@noisesmith no, I guess not. By definitions I meant function definitions (as opposed to calling a function).

2021-01-01T23:52:11.260600Z

one thing I've done for this is to require without a vector when requiring a namespace for its protocol extensions

2021-01-01T23:52:22.260800Z

most style guides say to never use require without the vector though

2021-01-01T23:53:23.261200Z

(ns my.ns
  (:require extend.foo.to.bar
            extend.foo.to.baz
            [code.i.call.directly :as directly]))

2021-01-01T23:54:10.261500Z

the require is happening for a side effect (the fact that something gets extended by that ns)

2021-01-01T23:54:25.262100Z

so none of the require features that you'd use a vector for actually make sense

2021-01-01T23:58:16.262700Z

Thanks @alexmiller, the tap worked