Fork me on GitHub
#clojure
<
2019-11-26
>
andy.fingerhut00:11:29

Isn't part of the issue with the desire that some would like it to work across both clj and cljs? I think the expression Sean gives above works for clj only.

hiredman00:11:29

no I mean, I don't understand the desire to use alias like that at all

hiredman00:11:45

I mean, I understand mechanically why people want it, and it does

hiredman00:11:20

but even using namespaced keywords, I never use alias to create a short way to type them

andy.fingerhut00:11:26

You type fully namespaced keywords out manually each time, and/or copy/paste, or Emacs dynamic abbrevations, etc?

andy.fingerhut00:11:14

Certainly I think some devs might not be taking better advantage of plain old copy/paste as often as they might.

hiredman00:11:05

I copy and paste and use tab completion

andy.fingerhut00:11:15

but I suspect it is born from the simple observation that they can easily create aliases for vars in other namespaces, so why not keywords?

hiredman00:11:24

maybe it is a sort of circular thing, they see aliases in examples, so they use aliases, and because they use aliases they it is annoying that cljs doesn't have them. and instead of walking all the way back and rethinking the decision to use aliases, they just want aliases in cljs?

andy.fingerhut00:11:02

People use aliases for namespace on vars all over both clj and cljs

andy.fingerhut00:11:11

Portably, in cljc files, too.

hiredman00:11:23

it isn't the same thing though

hiredman00:11:18

which makes me think, it is a shame the namespaces for keywords and namespaces for code are both called namespaces

Alex Miller (Clojure team)01:11:13

yes, we try to use "qualifier" for the first part of keywords/symbols these days. the qualifier may correspond to a namespace, or may not.

❤️ 4
andy.fingerhut00:11:47

I'm happy to get a deeper understanding of the differences, which I haven't thought through deeply, but at least at the level of X works for Y, why doesn't X also work for Z? kind of analogy reasoning, it is a reasonable question to ask, I think.

hiredman00:11:12

namespaces for code are a very formal thing, the runtime keeps track of them, and there are rules about them, and they exist independently of the names in them

hiredman00:11:31

keyword namespaces are just prefixes

hiredman00:11:56

like, a keyword is basically a pair [namespace-part, name-part]

andy.fingerhut00:11:31

Maybe it is a shame they are called the same thing, but that name is enshrined by Clojure core docs and functions like namespace and name, from folks that are usually pretty careful about what they call things.

hiredman00:11:49

well, they are literally namespaces

hiredman00:11:06

but calling them the same thing leads people to thinking they are connected in someway

andy.fingerhut00:11:34

They are connected in at least one way -- require with :as to create an alias for a namespace, you can use the alias both for Vars and for keywords.

andy.fingerhut00:11:26

Will be AFK for a while -- flight landing soon-ish 🙂

Alex Miller (Clojure team)01:11:45

these days we try to prefer the word "qualifier" for the first part of keywords and symbols

Alex Miller (Clojure team)01:11:08

as in qualified-symbol?, qualified-keyword? etc

Alex Miller (Clojure team)01:11:35

the qualifier may correspond to a namespace or an alias, or neither

pinkfrog01:11:53

how do you do authentication/authorization/session management in clojure?

pinkfrog01:11:48

one option: go with pure clojure land, e.g., buddy, but I am not sure for the maintenance and future support

Rex01:11:09

is your concern over buddy mostly about how inactive it currently is?

Rex01:11:05

I'm told that unlike Java where libraries tend to get updated regularly, Clojure libraries on the other hand live much longer

Rex01:11:33

so you can make use of Clojure libraries even if they were made a while back and be sure that it will work just fine

Rex01:11:51

I guess it's a bit more problematic when it comes to support/fixes/patches/etc. especially for a security library

pinkfrog01:11:35

yes. that’s what I worry about. It still feels a little bit unsafe even people claim clojure world doesn’t care about the recent update time of a library.

pinkfrog01:11:12

the other option is: go with java libraries, e.g., spring security, but it seems too bloated, and I worry about the inter-op.

pinkfrog02:11:25

@seancorfield what’s your dev env? intellij+cursive or emacs+cider ?

seancorfield03:11:12

@UGC0NEP4Y neither. Atom + Chlorine + Cognitect's REBL. No nREPL, no CIDER, no dev dependencies at all.

seancorfield03:11:43

Just start a socket repl in any process, connect Chlorine, and that's it.

sogaiu13:11:05

fwiw, cursive now has some socket repl support

seancorfield16:11:04

I don't like IntelliJ 🙃

sogaiu17:11:57

sure, not a huge fan either -- but the debugger in cursive is very helpful on occasion

hiredman02:11:56

A while ago someone mentioned Apache shiro(a Java library for all that) and it looked interesting but I haven't actually used it yet, just bookmarked it for the future

didibus02:11:30

Ya, I think Shiro is a good option if your using a servlet server like jetty

didibus02:11:45

It's very actively maintained

didibus02:11:33

I think in theory it is possible to use in non servlet environments as well, people say you can even use it for command line apps. But I think in those cases you have more to manually setup

Setzer2210:11:25

hi! how can I import two Java classes with the same base name? I've tried this but the compiler complains about Foo being already defined:

(ns my.ns
  (:import [my.first.package Foo]
           [my.other.package Foo]))

Setzer2210:11:06

however, if I just add the fully qualified name, like this, the compiler also complains about ns not conforming to its spec:

(ns my.ns
  (:import [my.first.package.Foo]
           [my.other.package.Foo]))

Setzer2210:11:32

Oh, I see. From the docs (https://clojure.org/reference/java_interop), I seems that the only way to do it to not import either class and use my.first.package.Foo or my.other.package.Foo everywhere in the code

p-himik10:11:04

Maybe you could import one and use FQN for the other? Should save a bit of typing.

Setzer2210:11:24

Thanks! in my case, it's not that big of a deal. My main concern was that I thought my code wouldn't work without the import, but apparently that's not the case, as using a fully-qualified-name will get the class even if not improted 👍

Alex Miller (Clojure team)13:11:02

Yeah, you have to fq at least one of them

sudakatux10:11:30

at least for me its morning 😛. Question is there a function that lets me apply a transformation to a stream... meaning i want to consume a stream make an operation and return a stream (unknownFunction myTransformer (slurp myStream))

vlaaad10:11:44

slurp returns a string, not a stream

vlaaad10:11:59

but usually you want map

vlaaad10:11:36

your stream is an input stream of bytes? you want to transform individual bytes?

sudakatux10:11:18

yeah. so i would like it as a string first. but i would imagine that would be part of my transformation

vlaaad10:11:43

string as in lines of text?

sudakatux10:11:06

yeah as in html

vlaaad10:11:09

there is line-seq for that that works on a reader

vlaaad10:11:56

(->> (io/reader "my-file") line-seq (map str/upper-case))

vlaaad10:11:37

(io/reader should be used with with-open though)

sudakatux12:11:42

actually map did not work 😞

sudakatux12:11:47

Don't know how to create ISeq from: clj_http.core.proxy$.FilterInputStream$ff19274a

sudakatux12:11:44

that why i supposed i needed to kind of consume the stream and re-create one

sudakatux12:11:39

though it sounds its not the ideal way either because of performance

sudakatux12:11:55

so to put you in context the stream is an http response. I would like to apply a transformation and return the transformation

sudakatux12:11:15

but as a stream

sudakatux12:11:47

as the same type i receive

vlaaad13:11:04

line-seq works on reader, not stream

sudakatux13:11:26

because i could not figure out a way to do it.

vlaaad13:11:35

you have input stream, you should coerce it to reader

vlaaad13:11:12

(require '[clj-http.client :as http])
(require '[ :as io]
(->> (http/get "" {:as :stream}) :body io/reader line-seq (map count)) ;; => result is (98822) (single line of 98k characters)

vlaaad13:11:00

that is, if you want to process your input stream (which is a stream of bytes) as lines of text (which should be first converted to a stream of characters — reader, and then splitted on newlines)

sudakatux13:11:16

i would love to have it as a whole

vlaaad13:11:33

it all depends on what you want to do with that stream. parse it using some different library? it may have a way to consume input streams

sudakatux13:11:52

because if its a json i would like to apply a transformation on the json

sudakatux13:11:43

so I would like to apply a transformation {a:2} => {a:4}

vlaaad13:11:17

I think in that case you should just load it as json

vlaaad13:11:43

clj-http can parse as json

sudakatux13:11:04

so basically i do need to consume it and then re-create the stream with io/reader right?

vlaaad13:11:08

I don't know implementation details of clj-http, but it probably just sends input stream to json parser, so there is no "hold json as string in memory" step

vlaaad13:11:56

it seems to be using cheshire, which can parse json from input streams directly

vlaaad13:11:12

probably just {:as :json} will be enough

sudakatux13:11:45

cool thanks i think... you unblocked me 🙂

vlaaad13:11:00

not enough, actually 🙂

vlaaad13:11:14

you need to add dependency on cheshire

vlaaad13:11:40

clj-http checks if it exists and if it does, uses it to parse as json

sudakatux13:11:17

i think for now what i was actually looking for is io/reader I do need the json part too but i can kick that for the future for now

vlaaad13:11:46

so this worked for me:

vlaaad@stoldt1220 ~> clj -Sdeps '{:deps {clj-http {:mvn/version "3.10.0"} cheshire {:mvn/version "5.9.0"}}}'
Clojure 1.10.1
user=> (require '[clj-http.client :as http])
nil
user=> (http/get "" {:as :json})
;; lots of json

sudakatux10:11:57

ohh cool i can then use map directly then

sudakatux10:11:22

cool I think thats what i was looking for thank you

yuhan11:11:13

Is there a way to programatically obtain the source location for protocol implementations?

yuhan11:11:21

Say I have a protocol from a library (defprotocol Flippable (flip [x)) and then extend that protocol elsewhere in different namespaces

(ns my.app)
(extend-protocol other.lib/Flippable
  Pancake
  (flip [x] ...))

yuhan11:11:00

Then given the function flip and type Pancake, I want to somehow get the file/line number of the extend-protocol expression

souenzzo13:11:07

(clojure.pprint/pprint other.lib/Flippable)

(into {}
      (map (comp (juxt identity meta) key))
      (:method-builders Flippable)) 

souenzzo13:11:10

(let [{:keys [impls]} Flippable]
  (into {} (for [[k v] impls
                 [method obj] v
                 :let [var (resolve (symbol (first (string/split (str obj)
                                                                 #"\$"))
                                            (name method)))]]
             [k (assoc (meta var)
                  :var var)])))

yuhan15:11:08

Sorry, I don't understand what the above is supposed to achieve - I'm trying to get the location of the method implementation for a particular type, not the protocol definition

yuhan15:11:04

The context for this is tooling support - a protocol or multimethod may have its implementations scattered across many namespaces, and it woudl be nice to be able to "jump-to-definition" for a given type for debugging purposes.

souenzzo15:11:23

I couldn't get what you wanted / needed, but I share my path Var's usually contains file line metadata, but it do not work for protoocls 😞

abdullahibra13:11:06

hi everyone, why global atom isn't shared between deftest functions ?

weavejester16:11:21

Does anyone know of a good library for coercing column names and values from SQL results?

weavejester16:11:15

e.g. {:foo_id "test"} to {:foo/id :test} given some definition like [:foo :foo_id keyword name]

weavejester17:11:59

The result builders look interesting. Thanks for pointing them out.

weavejester17:11:37

Though it looks like converting to next-jdbc might be more work than necessary.

weavejester17:11:52

Or maybe not… looks like there’s a get-datasource function for backward compatibility. I’ll investigate further.

kirill.salykin19:11:59

happy to help, btw, there is the new functionality about to be released - middlewares. commits are on master

dominicm16:11:45

Does it have anything to do with sql?

dominicm16:11:54

Notice that the value changed

dominicm16:11:38

https://github.com/riverford/mappings is really interesting in this space if you're not after something sql specific

weavejester16:11:48

Thanks @dominicm, that looks interesting.

didibus16:11:51

(sc/coerce `(s/map-of keyword? int?) {"foo" "42" "bar" "31"})
; => {:foo 42 :bar 31}

kenny17:11:35

Does anyone remember what dependency combination will fix this exception?

No implementation of method: :has? of protocol: #'clojure.core.cache/CacheProtocol found for class: clojure.core.memoize.PluggableMemoization

kenny17:11:08

Ah, forcing the latest core.memoize seems to do it.

Nir Rubinstein17:11:34

@weavejester - saw this a couple of months ago, maybe it can fit your needs? https://github.com/noprompt/meander

weavejester17:11:19

Might be a little too generic, but thanks anyway 🙂

ro618:11:18

I have a collection of email messages as Clojure data called threads that I'm trying to extract some info from, mostly via string/HTML parsing. Sometimes the messages have an unexpected format and for now I just want to ignore those errors. Something weird is happening when I eval at the repl. (map #(try (all-info (:body %)) (catch Throwable th nil)) threads) gives: Error printing return value (IllegalArgumentException) at clojure.core/-cache-protocol-fn (core_deftype.clj:583). No implementation of method: :date of protocol: #'tick.core/IExtraction found for class: nil The specific error doesn't really matter, what's weird to me is that it shows up at all since I'm catching everythng. Even weirder, (map #(try (dump (all-info (:body %))) (catch Throwable th nil)) threads) works as expected, returning the results without any error. dump is just a fn that pretty-prints its arg and returns it. I don't understanding why wrapping in a printing fn would affect the try/catch behavior.

john-shaffer18:11:00

Is all-info returning a lazy-seq? It probably is all-info calls map

ro618:11:02

No, all-info just returns a map: (defn all-info [thread] {:confirmation-number (second (re-find SUBJECT_CONFIRMATION_REGEX (subject-1 thread))) :departures (departures (html-resource (StringReader. (message-1 thread))))})

john-shaffer18:11:27

For a lazy-seq, the values aren't realized until they are requested. In this case they are being realized when the REPL looks at them to print them, which is past the try form

ro618:11:55

I see, so the dump call would realize the seq earlier

john-shaffer18:11:56

If any of those are lazy, you can get that behavior

ro618:11:05

Wow, that is a tricky little interaction, thanks @jshaffer2112, saved me a while there. Do people generally just sprinkle in into calls or something to coerce to collections explicitly?

john-shaffer18:11:12

If I want instant realization, I use vec or mapv (mapv is just map that returns a vector instead of a seq)

ro618:11:52

Ok. I think the laziness is coming from a for buried inside departures.

john-shaffer18:11:00

But it's usually not for that reason. That type of error catching is really hard to debug. I would prefer to filter out things that will cause that type of error

john-shaffer18:11:56

and do any necessary try right around where the error can occur, not in a parent function

john-shaffer18:11:31

Yes, for is lazy. Normally laziness is good to have, so I rarely force realization

borkdude18:11:42

instead of (try (for ...) catch Ex e) you could write (for [i [...]] (let [x (try ... catch )]), i.e. make the error handling more local

borkdude18:11:58

at least, that's one way to do it

john-shaffer18:11:35

Usually, yes. Those have different behavior though. (try (vec (for ...) catch Ex e) will return nil if anything inside causes an error, while the second example will have a nil for each value that caused an error

ro618:11:04

Right, I'm just being lazy (pun intended) at this point since it's early prototyping on a side project. Also, it turns out that any message that doesn't parse for any reason is irrelevant anyway, so I'd rather just express that once at a high level than catch a bunch of specific parse failures, only to wrap and propagate them up for the same effect.

john-shaffer18:11:12

You could put the try inside all-info then, and just call (map #(all-info (:body %)) threads)

john-shaffer18:11:28

You would have to realize departures, so (vec (departures ...)) maybe

ro618:11:25

True, that might be better. It's interesting to see how laziness interacts with everything here. It feels like a non-local effect. Haven't been bitten by that before.

andy.fingerhut18:11:25

Laziness interacts in odd ways with lots of things: dynamic binding, side effects of most kinds, and exceptions.

john-shaffer18:11:18

Things go so much smoother if you write as many pure functions as possible

andy.fingerhut18:11:38

It is also something that you do not always notice in repl tests, due to the forcing of laziness caused by the P

ro618:11:19

Yes, that's definitely a good rule, but it's still interesting to think about. When you're in pure, data-manipulation code, laziness feels like a good default, but otherwise eager-by-default seems to fit better. I believe at one point Rich said laziness might not be as pervasive in the language if he'd landed on transducers earlier.

ro618:11:43

@jshaffer2112 Are you talking about pure to the point of using monadic composition for error propagation and avoiding try/catch?

john-shaffer19:11:33

No, I just filter out or just return nil for invalid values. I mean pure as in "when you call it, it does the same thing every time with no side effects". Not that it can't use side effecting operators like try-catch internally, just that they can't escape

john-shaffer19:11:38

I might throw IllegalArgumentException, and you can find ways to crash things, but usually exceptions are from programming errors

john-shaffer19:11:17

I want to give spec a try though. Then it'll be "pure as long as the spec validates"