Fork me on GitHub
#clojure
<
2018-06-21
>
tbaldridge01:06:10

The problem is, the parts that don’t match are parts that I use fairly often. Vars, core interface names and methods, numerics, type hints, are all “advanced features” I use everyday and they’re completely different from CLJ and CLJS

4
danm14:06:25

If I have passed a class into a function as a var (e.g. (defn foo [klass] ...), how can I instantiate an instance of that class? (new klass) of course is expecting a class called klass, not using the value of the variable

noisesmith16:06:26

small nitpick about terminology here, a var in clojure is an instance of clojure.lang.Var which is a mutable container holding a single value plus metadata, local bindings are not vars, they are regular values (unless you use with-local-vars which-- probably nobody needs)

danm14:06:48

I was wanting to call it like (foo Exception)

darwin14:06:21

try (klass. <args>)

bronsa14:06:06

new is a special form that expects a literal class

bronsa14:06:18

foo. is just syntax that desugars to new foo

4
bronsa14:06:32

if you want to instantiate a class known at runtime you’ll have to use reflection

bronsa14:06:37

(.newInstance klass)

bronsa14:06:00

if you need to instantiate it with parameters you’ll have to use some more advanced reflection and use .getConstructors

bronsa14:06:12

or use clojure.lang.Reflector/invokeConstructor which does it for you

bronsa14:06:43

(and also does type disambiguation in the case of multiple available constructors)

borkdude14:06:42

there is set/join, I need that, but more like set/left-join if there is such a thing 🙂

borkdude14:06:09

I don’t understand this behavior:

(set/join #{{:a 1}} #{{:b 2}})

borkdude14:06:52

shouldn’t that return an empty set because no common keys?

jmckitrick14:06:02

Why would explain hang on a simple spec?

borkdude14:06:23

maybe it’s recursive? 😉

jmckitrick14:06:37

But valid would pass?

jmckitrick14:06:53

Let me check 😉

jmckitrick14:06:08

Nope, they all reduce to primitives (int? and string?)

jmckitrick14:06:42

Wait, I might have found something…

jmckitrick14:06:51

Hmm. No good. This is really odd.

bronsa14:06:16

@borkdude no it’s correct

bronsa14:06:40

if there’s no common keys between 2 rels, natural join becomes cross product

borkdude14:06:16

is this the same in sql?

bronsa14:06:19

>If there are no common column names, NATURAL JOIN behaves like JOIN ... ON TRUE, producing a cross-product join.

bronsa14:06:03

it follows from the relational algebra definition of ⋈

borkdude14:06:49

cool, thanks 😄

sundarj15:06:11

@borkdude you can have it return an empty set instead by passing a keymap

borkdude15:06:24

yes, I figured. I’ll do that just to be sure — thanks

jmckitrick15:06:47

@borkdude The spec causing the issue is not recursive. However, it does derive from an existing spec.

jmckitrick15:06:12

So (s/def ::value string?) and then (s/def ::old_value ::value)

jmckitrick15:06:34

Why would that be an issue?

Alex Miller (Clojure team)15:06:42

there are a couple known issues with aliased specs like that but I don’t know why you’d see hanging. do you have a full repro?

jmckitrick15:06:00

Let me try to whip one up….

Alex Miller (Clojure team)15:06:54

might also be possible you have an inconsistent repl state - specs are compiled at the point of definition and downstream specs should be recompiled if they change

Alex Miller (Clojure team)15:06:13

occasionally that can lead to seeing something weird

jmckitrick15:06:19

I’ll keep that in mind.

jmckitrick16:06:31

Has anyone put together a strategy for integration of spec with unit testing? Like a checklist, perhaps, of techniques to use and when they’d be appropriate? If not, I’ll just experiment.

jmckitrick16:06:39

For example, I have a db layer, a core/app layer, and the web endpoints. So I can use ring-mock for the endpoints, and transactions for testing the db raw functions.

jmckitrick16:06:33

Then, I guess I can fdef the db functions, and that would let me mock them in stest/instrument for the unit tests in core/app….

seancorfield16:06:46

@jmckitrick If you have function specs, then you could instrument the namespace under test in your fixture (an uninstrument it at the end).

jmckitrick16:06:04

You beat me to it 😉

seancorfield16:06:25

But check isn't really intended to be run as part of unit tests -- it's a different kind of test (that may take a long time to run).

jmckitrick16:06:42

Ah, good to know. So more for REPL based testing?

seancorfield16:06:02

You can use exercise to generate random, conforming data for use in unit tests. So that's another aspect.

jmckitrick16:06:50

I have a few minimal examples I used to demo Clojure to our CTO, but now I need to come up with a comprehensive strategy for each project we do going forward. It’s a Scala shop, so everyone is worried about types, lol.

seancorfield16:06:29

Well... Spec != types so the you probably don't want to "spec everything", just boundaries.

jmckitrick16:06:30

I demoed exercise, sample, generate, instrument, check, and summarize-results

dpsutton16:06:34

Object int or double is all you need

jmckitrick16:06:43

That’s my thought as well, @seancorfield

ghadi16:06:55

yeah make sure that spec != types is very clear. Type-oriented people will definitely try to analogize

jmckitrick16:06:43

What else do you emphasize to those who think types are essential to enterprise projects? Assuming we got the go-ahead to use Clojure, that is. How to assuage their fears, really…

seancorfield16:06:38

There's a huge shift in how you work, from Scala to Clojure. REPL-driven development (as much of a cliche as that is) means a very different way of "testing" code as you write it.

jmckitrick16:06:31

No question about it, I’ve loved REPL-driven development since discovering common lisp. But when I’m talking to Scala devs, and I’m not so much convincing them to try Clojure as to accept that it will be reliable….

seancorfield16:06:56

@jmckitrick We initially tried Scala and moved to Clojure because Scala didn't really "fit" how the team liked to work (they were used to dynamic languages). If your team is happy with Scala, I don't know that you will successfully migrate them.

ghadi16:06:57

specs are a la carte, you can apply them to third party libs, etc. I think there is a really great sum up in a StuH talk from StrangeLoop 2016 / 2017 -- in the first ten minutes

seancorfield16:06:06

How are you intended to add Clojure to what you're already doing?

ghadi16:06:12

(there's a table comparing specs and types)

jmckitrick16:06:16

I have to admit, it’s addicting to make a change, and see a bunch of red squiggly marks telling you what to fix next. 🙂

ghadi16:06:44

don't underestimate the time it will take to get past the beginner's hump

jmckitrick16:06:56

@seancorfield We are writing services and small UI projects for our team in Clojure/Clojurescript.

jmckitrick16:06:23

I have one other dev on our product team, and he’s a huge fan and is productive already. It’s his project I’m spec-ing.

seancorfield16:06:40

OK, so they are isolated, somewhat independent projects?

jmckitrick16:06:28

A third dev has already contributed code, and really likes it since he had former Clojure experience.

seancorfield16:06:29

And you're adding specs, after the fact, to an already working project? For what purpose specifically?

jmckitrick16:06:44

Yes, isolated, and calling other services or the db

jmckitrick16:06:03

It’s sort of an example project. I want the new dev to see how spec can/should be used. He was focused on delivering the functionality, while I add in specs.

jmckitrick16:06:21

Not an ideal approach, but it’s a start.

justinlee16:06:11

@jmckitrick are you using bare spec or have you found any of the helpers to be, uh, helpful? like expound, orchestra, spell-spec, or spec-tools for example

jmckitrick16:06:36

I just starting using expound, but not the other 3.

jmckitrick16:06:00

I have today and tomorrow dedicated to spec, so now’s the time!

ghadi16:06:38

expound is nice. I think orchestra is a bit stubborn about not understanding why instrumentation doesn't instrument the function return

ghadi16:06:24

it's ok to be contrary, its rationale doesn't persuade me

justinlee16:06:29

@ghadi is this a discussion that has happened in an issue somewhere? i did a quick search for ‘return’ on the readme and don’t immediately follow your point

bbrinck19:06:58

There’s a good discussion with @U064X3EF3 on this topic in the comments on this Reddit post https://www.reddit.com/r/Clojure/comments/7g4fl0/are_return_types_a_black_eye_for_clojure/

bbrinck19:06:41

I personally find validating return values useful for the reasons explained here https://www.reddit.com/r/Clojure/comments/7g4fl0/comment/dqkgrcb

justinlee21:06:44

crikey why does everything have to be so philosophical and complicated 🙂

justinlee21:06:19

assuming you are bhb i totally agree with you

bbrinck21:06:48

Ah yes reddit is one of the few places I’m bhb not bbrinck

ghadi16:06:36

I haven't tried spell-spec nor know what it is. spec-tools doesn't seem necessary, and might interfere with a nascent team

ghadi16:06:15

@lee.justin.m I believe there is some threads on the mailing list

ghadi16:06:36

I'd definitely recommend expound for a nascent team. It's easy to put it in your user.clj and reap benefits

justinlee16:06:56

you should check out spell-spec. pretty cool piece of tech from bhhauman. (in my case it has a feature for closed maps that I want but I won’t turn down better error messages)

jmckitrick16:06:07

I’ll start with raw spec and expound, so I understand the fundamentals, and go from there. My first goal is to establish some best practices.

jmckitrick16:06:54

So when spec-ing boundaries, is that generally just library entry points and web service endpoints? Or would it also include any internal API and persistence layer as well?

jmckitrick16:06:25

I realize there isn’t a right or wrong answer, I’m just curious what the general consensus is….

leblowl17:06:10

I can share my limited experience. I recently spec'd an internal API/persistence layer. It was my first spec and it seemed like a nice idea to return more meaningful errors over SQL errors for myself/other developers. My web endpoints will probably call the CRUD-like layer and use the same validation. I am hoping to use alexanderkiel/phrase to convert the spec explanations to readable messages for the user. One thing that was a little funny (I also had the same experience with Django DRF serializers) is that when I have a create function and update function... I end up with 3 different specs since the fields are different for creating an object, partially-updating an object and the whole object itself. Whenever I have a new function with different parameters I create a new spec and sometime a new return spec if I validate the response. So in this way I can have a lot of specs and I'm not really sure if there is any way to reduce that.

👍 4
seancorfield17:06:58

I've found spec to be much more useful via conform and valid? than via instrument but YMMV. I've found exercise to be useful in generating "example test" data for situations where there are side-effecting functions in play (e.g., a database, a service call; where I don't want to mock the side-effects or it's "too hard"). In order to use check you've really got to a) have a side-effect-free function to check and b) figure out useful invariants of your function -- and the latter can be hard for anything but the simplest function (and, of course, for simple functions correctness may be obvious and not worth testing 🙂 )

justinlee17:06:06

@seancorfield when you say you find it “much more useful via conform and valid? than via instrument” does that effectively mean that you only use spec as tool during tests rather than during development? or do you mean you manually instrument like you would an assertion library? (or something totally different)

jmckitrick17:06:46

@seancorfield I thought it was just me who felt that way! I use valid? frequently, and exercise during development. Then I just fall back to unit testing and with-defs for mocking.

jmckitrick17:06:18

I’m looking for an effective way to integrate instrument into our testing strategy.

seancorfield17:06:56

@lee.justin.m I mean we use it for validation/conformance of data in production code, much more than we use it for function argument/return checking.

👍 4
seancorfield17:06:24

We use instrument from the REPL while developing but only use it in one place as a fixture in one set of unit tests:

(def ^:private test-member-id 12345)
(def ^:private test-facebook-id 123456789)
(def ^:private facebook-me {:id test-facebook-id :name "Test Harness"})
(def ^:private ^:dynamic *me* facebook-me)
(defn instrumented-and-stubbed
  "Run tests with fake Facebook session."
  [t]
  (st/instrument (st/enumerate-namespace 'ws.facebook))
  (with-redefs [facebook/me (fn [_] *me*)]
    (t)))
and then
(use-fixtures :once instrumented-and-stubbed)

seancorfield17:06:07

(we don't both un-instrumenting that but we probably should)

arohner19:06:00

is liberator capable of generating swagger? Is any other REST library?

nha08:06:27

and yada, from the same author as Liberator https://github.com/juxt/yada

jmckitrick19:06:47

compojure-api, if you haven’t heard already, can do so.

arohner19:06:01

oh very cool, thanks!

shayanjm20:06:03

Does anyone know of an http library like Aleph or Ring that supports HTTP/2 out of the box?

bbrinck20:06:51

@jmckitrick if you find yourself wishing for closed “keys” specs, definitely check out spell spec. I also like orchestra a lot.

bbrinck20:06:52

One value of spec is documentation, and w/o orchestra, I had no confidence that my return specs were correct

bbrinck20:06:30

(For many functions. A small number could be validated with ‘check’)

seancorfield21:06:37

Although (doall (map my-fn my-data)) and (seq (mapv my-fn my-data)) produce slightly different types (`LazySeq` vs PersistentVector$ChunkedSeq) they both produce fully realized sequences and benchmarking suggests the latter is quite a bit faster (for large my-data collections). Can anyone think of a non-pathological situation where swapping the former out for the latter would introduce bugs or break code that used the resulting sequence?

Alex Miller (Clojure team)22:06:23

I would say if it mattered, that would be bad

simple_smile 4
noisesmith22:06:11

chunking behavior of consuming the result lazily - but if that breaks the consumer I think it's fair to blame the consumer

noisesmith22:06:55

user=> (take 3 (map print (seq (mapv identity (take 40 (iterate inc 0))))))
(nil nil nil)012345678910111213141516171819202122232425262728293031
user=> (take 3 (map print (doall (map identity (take 40 (iterate inc 0))))))
(nil nil nil)012

seancorfield22:06:23

Thank you both. Yes, chunking was the only thing I could think of and I didn't think the producer of the sequence should be blamed for that 🙂 (this relates to some code in clojure.java.jdbc).

jlfischer23:06:28

Am I wrong in assuming that map destructuring doesn't work with namespaced keys?

jlfischer23:06:36

Oh, perfect, thanks!

8