Fork me on GitHub
#clojure
<
2019-04-18
>
mars0i02:04:23

If the lib you need requires concrete inheritance, then you have to do it anyway. In a specialized domain, you may not have a choice. And the Java programmers who wrote it are just doing what makes sense in that world. I personally would rather Clojure was a little more accommodating of this situation, but I accept that this is probably unlikely to change. (I have fought the gen-class and contained it.)

mars0i02:04:11

Ah, got it. Too tired. Feet stuck in it.

ahungry02:04:47

I like the fact that I can use a class from defrecord as an early guard against invalid inputs to calls I want to make on it, for instance:

(defmulti alive? class)
         (defmethod alive? UnitModel [{:keys [hp]}]
           (> hp 0))

ahungry02:04:46

But, if there was any CL CLOS like facility, it would be even nicer if I could have a more specialized call like:

(defmethod alive? UndeadModel [{:keys [hp]}]
  (< hp 1))

john04:04:35

can't you do that with hierarchies?

ahungry02:04:39

to me, its nicer to read a very small specialized/dispatching function, rather than a big case/cond within a defn that has to hold all current and future logic

hiredman02:04:06

(defn alive? [{:keys [hp]}] (< hp 1))

hiredman02:04:38

in general, using defrecords purely as data containers is kind of gross, use a map

ahungry02:04:49

I want flip flopped alive logic - if the unit is normal, hp > 0, if its undead, hp less than 1. If its some future type, like "plant", maybe its alive or dead based on which season of the year it is

ahungry02:04:47

I mean I could just use a 'type' key in a map and a case to choose which fn to dispatch to

ahungry02:04:53

just seems odd there is no built in facility to handle it

hiredman02:04:12

you could do that, and you can use the hierarchy facility to do whatever

hiredman02:04:23

but using it is kind of gross and weird, it is very rare to come across

ahungry02:04:28

Started with a plain map, was attempting to refactor for cleaner code

ahungry02:04:00

basically, a combo of defrecord / spec and a custom factory fn (`make`) so I can ensure I always have valid state units in game

ahungry02:04:14

I was just hoping to branch it out into MobModel and PlayerModel actually, so I could keep AI logic separate from player specific functionality - in current iteration it is just plain maps and mobs become mob by having the :mob key added to their map

ahungry02:04:41

just seems kind of fast and loose and future error prone (when I have to backtrack through 100 function calls in the future and identify all fields a unit should have)

👍 4
hiredman02:04:43

spec works much nicer with plain maps vs records

hiredman02:04:14

I am not sure what you mean about back tracking through 100 function calls, if you have a spec that says what should be in a map, you have a spec

ahungry02:04:31

sorry that was under the current iteration where I didn't really bother with it

hiredman02:04:36

you can insert validation where you want it

hiredman02:04:51

or leave it out, or only validate when running tests, or whatever

ahungry02:04:47

What am I screwing up on the spec here?

mars0i02:04:03

A defrecord is simpler than spec if you don't need spec for other reasons.

ahungry02:04:08

The error is: Execution error (ExceptionInfo) at expound.paths/in-with-kps (paths.cljc:183). Cannot convert path. This can be caused by using conformers to transform values, which is not supported in Expound

ahungry03:04:17

I'm assuming my args have to be wrapped in s/cat or something

bbrinck03:04:29

Yeah I think you’re correct - you need an ‘s/cat’ for args

ahungry03:04:46

So, even with s/cat it works now, with good input

ahungry03:04:50

but bad map, it just throws that error

hiredman03:04:53

Also it is better to use namespaces keys

ahungry03:04:54

vs letting me know a bad instrumentation

ahungry03:04:12

namespaced keys is a lot of work when its user inbound json populating the keys though

ahungry03:04:21

well, maybe there is a wrapper for namespace keys to/from json

ahungry03:04:37

i remember looking and flat maps, not terrible, nested ones, bad

hiredman03:04:28

I dunno about the expound stuff, I think I am using it somewhere to get some nicer spec errors in one place, but otherwise I am not familiar with it

bbrinck03:04:43

Hm, that might be a bug in Expound then related to errors on ‘fspec’ if this is happening on latest expound.

ahungry03:04:09

afaik, i'm not explicitly calling it explicitly anywhere, unless cider (Emacs) is injecting some call - I am on clojure 1.10

bbrinck03:04:44

Perhaps a dependency is using it?

ahungry03:04:53

(alive? {:hp 30 :name "Bob"}) - that call is fine, works alright. This one: (alive? {:xhp 30 :name "Bob"}) error

bbrinck03:04:47

(I saw something similar with return values for fspec, that are keys, so I think it might be expound bug). Feel free to file a bug and I’ll look into it.

hiredman03:04:20

Something is pulling expound for you, and overwriting specs error reporting with it

bbrinck03:04:41

It’d be best to find what is doing that (maybe look at deps tree to start) but in a pinch you could reset the default printer. I’m on my phone but something like ‘set! s/explain-out s/explain-printer’

ahungry03:04:36

I guess that's what I get for running code I didn't fully read yet 🙂 (luminus lein template)

ahungry03:04:40

(alter-var-root #'s/*explain-out* (constantly expound/printer))

bbrinck03:04:23

Ah, yeah, that’ll do it :)

bbrinck03:04:35

@m131 do you have expound 7.2 as a dep?

bbrinck03:04:16

I looked closer at that code and now I’m not so sure why you’re getting that error. Just curious if you happen to have an earlier version.

ahungry03:04:38

It was 7.1, a definite PEBKAC error (I altered the templated clojure version from 1.9 to 1.10 and nothing else) 😞 7.2 does seem to fix it, thanks again!

john04:04:54

For dispatching, you may have fun with polymethods and dispatching off of s/valid? or whatever https://github.com/johnmn3/dispacio#spec-validation-dispatch

ahungry19:04:39

Very nice, thanks

kah0ona13:04:09

If I have a clj-time date-time (which is UTC), say (date-time 2019 4 18 12 0 0), but I want it to become the same date in Europe/Amsterdam, ie, it should be: 2019-04-18T12:00:00.000+02:00, how do I do that

kah0ona13:04:54

ie. i don’t want it to shift hours, ie. I don’t want to end up with 2019-04-18T14:00:00.000+02:00

kah0ona13:04:53

aah no it’s this: (.withZoneRetainFields input-date (DateTimeZone/forID "Europe/Amsterdam"))

sogaiu07:04:33

i don't know about in anger, but i've tried it a bit. i think @U38J3881W has too: https://oli.me.uk/2017/10/06/an-introduction-to-transcriptor/

Olical09:04:43

Yep, not in anger though either 😊 I wrote a lein plugin for it and found it interesting. I think a regular test suite still does it for me but it might suit others better!

fenton16:04:12

(meta ((fn [x] ^{:k 9} x) {:a 1})) ;; ==> nil 
(meta ^{:k 9} {:a 1})              ;; ==> {:k 9} 
(-> {:a 1} ^{:k 9} meta)           ;; ==> nil

Alex Miller (Clojure team)16:04:56

the ^ syntax is applied at read time to the next read form

dpsutton16:04:22

(-> {:a 1} ^{:k 9}) will throw a read error meaning you are putting it on the meta form

Alex Miller (Clojure team)17:04:17

this throws a read error because there is no "next" form to apply it to

Alex Miller (Clojure team)16:04:50

so in the first line, it's applied to the symbol x, which is not going to be ignored when compiling the fn. in the second line, it's applied to the literal map {:a 1} in the third line, it's applied to the symbol meta, where it won't do anything

Alex Miller (Clojure team)16:04:04

if you want to apply metadata to things at runtime, it's better to use with-meta

Alex Miller (Clojure team)16:04:07

(meta ((fn [x] (with-meta x {:k 9})) {:a 1}))  ;; ==> {:k 9}
(meta (with-meta {:a 1} {:k 9}))               ;; ==> {:k 9}
(-> {:a 1} (with-meta {:k 9}) meta)            ;; ==> {:k 9}

fenton17:04:28

okay...thank you!

Azrea17:04:21

Are there any weird gotchas I need to know if I'm combining clojure.core.async code with promises?

hiredman17:04:30

are you talking about clojurescript and js promises?

Azrea17:04:03

No, JVM clojure and Java Promises

Azrea17:04:21

I want to combine async code with http-kit because I had problems with Java blocking IO hanging

hiredman17:04:00

well, java doesn't have promises (at least not in the jdk)

hiredman17:04:56

if you are having trouble with blocking io, switch to non-blocking is only going to make your io problem harder to debug

Azrea17:04:25

The information I've found seems to imply that the trouble with blocking IO is inherent to blocking IO, an unreliability in linux's blocking select call, and that async IO will react to that unreliability better

noisesmith17:04:34

@atamiser a Clojure promise is just a container that starts empty and can only have a value assigned once - it's hypothetically useful to communicate between async operations, but has very few features

noisesmith17:04:52

and really a channel is a better fit if using core.async

hiredman17:04:34

clojure's promise is built around blocking (it blocks execution when deref'ed) so while combining it with core.async is possible (and core.async uses them under the hood here and there), in general you pickup core.async because you don't want threads to hang around blocked which is at odds with promises

noisesmith17:04:46

waiting on a promise can introduce the kind of deadlock core.async is designed to eliminate

Azrea17:04:57

Yeah, so no derefing in a go block

noisesmith17:04:11

a go block using channels is a much nicer alternative to js promise chaining, with the same semantics (each channel read or write in a go block is conceptually equivalent to a .then invocation)

Azrea17:04:50

Yeah, but the pure core.async HTTP client implementations are a tad barebones? Maybe a little immature

noisesmith17:04:50

you might want to look at aleph, which is dedicated to nonblocking IO with an abstraction that's very similar to core.async channels

noisesmith17:04:56

aleph uses manifold, which integrates directly with core.async as well

Azrea17:04:25

Nice, that works perfectly

Azrea17:04:44

I ran into it when looking at web servers, but glossed over that it integrates with core.async

hiredman18:04:12

cognitect's aws-api library make's use of cognitect http client library which seems to have a core.async interface which I haven't been able to find the source for, but seems to be get'able from maven, and appears to be apache licensed

dominicm18:04:32

I think it is closed source

dominicm18:04:44

I think this was mentioned in the talk

hiredman18:04:07

ah, I haven't seen the talk

ghadi18:04:08

what @hiredman said is true

ghadi18:04:13

it is not closed source

hiredman18:04:34

so if you felt adventurous you could grab that library and make some wild guesses at how to use it

Azrea18:04:07

That sounds very interesting, but somewhat fraught

ghadi18:04:24

there are a few limitations of the cognitect http-client (streaming support being the largest one)

ghadi18:04:49

we're thinking about whether/how to support that for aws-api

dpsutton21:04:55

i thought java defaulted strings beginning with a zero to base 8 when parsing? ie, (Integer/parseInt "09") should throw?

dpsutton21:04:05

is that cljs or am i just confused?

noisesmith21:04:45

that's for literals in source code, not parsing

dpsutton21:04:15

yes just remembered that's a read-string and literal issue. thanks @noisesmith

Alex Miller (Clojure team)21:04:53

the Integer/decode method can do this

noisesmith21:04:02

also since clojure defaults to longs, I almost always use Long/parseLong for such use cases

dpsutton21:04:25

was about to ask a question 🙂

dpsutton21:04:37

just making sure parseInt wasn't a footgun with radix

Alex Miller (Clojure team)21:04:53

yeah, that one assumes you know the radix

noisesmith21:04:35

=> (Long/parseLong "100" 32)
1024

giaweezy22:04:09

for those that use clojurewerkz.elastisch, my team recently moved from elasticsearch 5.6 to 6.4 and a majority of the functions broke, but were fixed by passing in {:content-type :json} when calling clojurewerkz.elastisch.rest.connect i.e.

(esr/connect host {:content-type :json})

giaweezy22:04:47

Apparently clojurewerkz.elastisch.rest.document.scroll-seq had a similar issue but i eventually fixed it by actually just copying the scroll and scroll-seq function from their github and just pasting it into the same .clj file

giaweezy22:04:46

Since scroll-seq returns a lazy sequence i think there's some weirdness with fully evaluating the rest calls which causes the content-type to be lost since the exception i was getting indicated a json parser error

giaweezy22:04:31

i verify this by doing a (take 5 (esd/scroll-seq ...

giaweezy22:04:29

figure i share in case some else out in the clojure community is also using the clojurewerkz.elastisch library and scroll-seq

Alex Miller (Clojure team)23:04:55

I only ask that you buy them :)

😂 4
4
💰 4