Fork me on GitHub
#clojure
<
2015-12-28
>
mudphone00:12:38

It all seems moot though, as I’m unable to require cljs.analyzer.api

aaelony01:12:08

is there a clojure core function that constructs a seq from a Java 8 stream?

aaelony01:12:35

hmmm, maybe that's a bad idea. perhaps staying in interop is better in this case. thx

seancorfield02:12:08

@aaelony: What's your use case here?

aaelony02:12:49

a java codebase at work that I'd prefer to interact with via clojure...

crocket03:12:47

Is boot a serious win over leiningen?

crocket03:12:18

The propaganda around boot seems to suggest that it's superior to leiningen.

crocket03:12:58

It seems each has its own advantages.

zcaudate03:12:24

well… the ecosystem around leiningen is so vast and tooling wise… I can’t ask for anything better

zcaudate03:12:15

I’ve never used boot… but someone should write a program that takes a leiningen plugin and makes it boot compatible

zcaudate03:12:18

that’ll be amazing

zcaudate03:12:42

we can run it on the entire ecosystem of lein-plugins 😃

seancorfield04:12:10

@aaelony: Well, using Clojure to do Java interop can be better than straight Java, insofar as there's less typing (in multiple ways simple_smile ) but it's certainly not as nice and "pure Clojure". How much pain you get will depend on the API of the Java code. (sorry for the slow response -- had to feed cats and get our dinner too!).

aaelony04:12:10

@seancorfield: thanks, but this question was only about java 8 streams

aaelony04:12:05

which offer their own filter, map, and reduce constructs

aaelony04:12:44

glad the cats are fed;)

seancorfield04:12:44

@crocket: We just switched from Leiningen to Boot at work (World Singles). We really want to move more of our build processes into Clojure but writing Leiningen plugins hasn't always been very easy for us. By converting to Boot, we've already been able to replace the plugins with simple Boot tasks, and move several other parts of the build into Boot tasks, and compose them. So we shaved about a minute off our build script because we're not firing up as many JVMs simple_smile

seancorfield04:12:10

@aaelony: Understood. If all you're working with is streams, you're not going to get much benefit from Clojure there.

crocket04:12:10

@seancorfield: Could boot be a short-term gain followed by a long-term loss? Long-term means several months down the line.

aaelony04:12:40

@seancorfield: yes, there be streams and there does not appear to be a stream/collection conversion, or perhaps interop is better anyway.

seancorfield05:12:16

@crocket: Our long term goal was to move more of our build process to Clojure and we can do that with Boot so that's a win over the long term for us simple_smile

crocket05:12:38

I was comparing boot with leiningen.

crocket05:12:46

Leiningen is ok for libraries and simple builds.

crocket05:12:01

Boot is better suited for customizing builds.

seancorfield05:12:06

I wasn't very impressed with Boot when it first appeared but revisiting it now it really has matured... the ecosystem is still young...

crocket05:12:29

An advantage is that boot could easily go beyond leiningen in scope since it's clojure code.

seancorfield05:12:36

Yeah, Boot is more than just a project build tool. But Leiningen has the templates which is a big plus, and it's pretty much ubiquitous in the Clojure world simple_smile

crocket05:12:07

Does boot not have templates?

crocket05:12:48

boot reminds me of gulp. I was using gulp on node.js

seancorfield05:12:20

We started out with Grunt, but the new front end project we're doing is using Gulp.

crocket05:12:57

Are you porting gulp builds to boot?

seancorfield05:12:30

No, Gulp is used by our front end team.

seancorfield05:12:42

We're moving an Ant script to Boot simple_smile

crocket05:12:23

I didn't like Ant because it was XML.

crocket05:12:38

Far inferior to edn or json.

seancorfield05:12:01

I've never liked Ant, but the alternatives were... mostly no better...

crocket05:12:05

Are you suffering the cost of writing and running tests on clojure? I heard that test costs become uneconomical in large projects in dynamic languages.

seancorfield05:12:50

Where did you hear that?

crocket05:12:11

A blog maintained by a haskell supporter. I never maintained large projects, so I don't have first-hand experiences.

seancorfield05:12:39

Haskell people don't like dynamically typed languages simple_smile

seancorfield05:12:48

We have 30,000 lines of Clojure.

seancorfield06:12:10

And about 7,600 lines of tests.

seancorfield06:12:41

But some of that is testing our REST API (which is written in multiple languages).

crocket06:12:57

He likes clojure, too, but he thinks haskell is more economical than clojure in large projects because of haskell compiler.

crocket06:12:04

How many lines would your project consume if it was written in C++?

seancorfield06:12:22

100,000? 200,000?

seancorfield06:12:20

(I used to maintain a code base that was about 250,000 lines of C++, back in the 90's)

crocket06:12:20

@seancorfield: How was your experience on large projects written in statically typed functional languages and dynamically typed functional languages?

crocket06:12:46

30,000 lines are still large by my standards.

seancorfield06:12:39

We have 89,000 lines of non-Clojure code alongside the 30,000 lines...

kopasetik06:12:25

OK, how do I refactor this solution?

kopasetik06:12:31

The problem that I solved...

kopasetik06:12:02

The solution I wrote...

seancorfield06:12:33

In the map you could just use * instead of #(* %1 %2)

seancorfield06:12:52

I think you can avoid the condition on bigint / int by using a N suffix on 13 and 10?

kopasetik06:12:11

Here are some more concise solutions...

kopasetik06:12:02

I want to get to the point that I can be that concise...

kopasetik06:12:22

At the same time… the more concise, usually the more difficult to follow

niwinz09:12:01

Hi! I found a very unexpected behavior of transients

niwinz09:12:20

Using assoc! function for assoc items to the transient associative data structure and it only associates 8 first elements discarding the rest...

niwinz09:12:40

I'm missing something or this is an expected behavior?

niwinz09:12:59

The same behavior happens in clojure and clojurescript

dm310:12:54

this is very strange indeed

mpenet10:12:57

It s normal, you re not supposed to bash it in place (it s not a java style mutable ref)

mpenet10:12:36

http://clojure.org/transients > Note in particular that transients are not designed to be bashed in-place. You must capture and use the return value in the next call. In this way, they support the same code structure as the functional persistent code they replace.

mpenet10:12:35

A lot of people misuse them in the wild sadly and the problem is not always obvious

jaen10:12:18

Say, if I want to extend equality what is the common practice? Say I have a new type SomeRecord and I want to make sure that both (= new-record any-existing-type) and (= any-existing-type new-record) work as expected.

niwinz10:12:19

@mpenet: I understand, thank for pointing me about bashing in place!

nha10:12:51

@jaen I think you can implement the IEquiv protocol

nha10:12:21

(at least it is so in cljs)

jaen10:12:15

Hm, searching the Clojure github repo for IEquiv returns nothing though ; /

niwinz10:12:55

IEquiv as far as I understand is cljs only

jaen10:12:11

It would have been nice if operators had multimethods you could extend on, but alas I don't think that's the case.

jaen10:12:41

I was just wondering how hard would it be to replicate Perl junctions so that they work in usual Clojure contexts, instead of requiring a new set of operators.

nha10:12:27

I think it is one of the differences between clojure and clojurescript : in cljs protocols are at the bottom

nha10:12:31

(which is good)

nha10:12:51

oops sorry bad link did not realize

niwinz10:12:08

This is something I missing in Clojure...

jaen10:12:43

Weird, Github search returns nothing for IComparable either. Is it broken or what?

nha10:12:59

Maybe it is only clojurescript then

niwinz10:12:58

@jaen clojure uses Object.equals

jaen10:12:58

@niwinz: Yeah, that sounds like a nice feature to have, being able to extend core types easily.

nha10:12:27

Oh so java interrop (equals, and also maybe hashcode and toString )?

jaen10:12:39

I think Dunaj was going in such a direction, but not sure if that extended to all the operations like +, *, and and the like.

jaen10:12:38

@niwinz: yeah, I noticed that while looking at the code of clojure.lang.Util/equiv, but this begs another question

jaen10:12:51

I can add equals implementation to my record

jaen10:12:06

But what should I add it to make sure it's symmetric?

jaen10:12:47

myRecord.equals(somethingElseEntirely) is just one direction of equality, what about sometingElseEntirely.equals(myRecord)

jaen10:12:32

And that's just equality, other operators probably don't have something equivalent.

niwinz10:12:39

hmm, as far as I know, equals contract is that only works in the same type of objects

niwinz10:12:03

so if you compare different types of objects it should return false (in java it will not compile because of type checking)

jaen10:12:49

Sure, but - since I was thinking about junctions - let's have a concrete example - it is entirely valid to want to (= a (junction/any 1 2 3)) where one side is Integer and the other is AndJunction<Integer>.

jaen10:12:12

They are nominally disparate types, but semantically should be comparable.

jaen10:12:04

In Scala that could probably be solved by implicit conversions, by lifting Integer to something like JunctionComparable<Integer> or something, but I'm not sure how that would be approached in Clojure.

jaen10:12:15

Maybe it's something that doesn't have a neat solution in Clojure.

niwinz10:12:53

If you see the set impl, it uses equals for just do that, receiving Object as parameter so I think you can do the same thing.

niwinz10:12:09

but, clearly you can't do it symetric

niwinz10:12:33

because you can't extend the integer type to behave as you want

jaen10:12:25

Yes, but that's just this once specific case again - of course you can just do (#{1 2 3} a) to the same effect as (= a (junction/any 1 2 3)) and all, one, none junctions can be rewritten in a similar way probably

jaen10:12:40

But there's no generic solution to this problem, that is extending the built-in behaviours.

niwinz10:12:46

The only solution that I found, is implement the equality check as your own abstraction

niwinz10:12:15

instead of using the clojure's one

jaen10:12:39

Right, but then you're building your own walled garden, since other libraries will not be using that ; /

jaen10:12:53

Would have been nice if Clojure had some base abstraction like that.

niwinz10:12:19

would be nice to have clojure implemented in terms of protocols instead of interfaces

niwinz10:12:21

as cljs does

jaen11:12:53

Being able to do (defmethod clojure.lang/equals [MyType _] ...) and similar (for things like multiplication, addition, comparision and such) would give a lot of flexibility.

nha11:12:15

Well I guess they realized that after (protocols came in clojure 1.2 I think)

jaen11:12:29

I think multimethods were in 1.0 though, so the same could have been achieved without protocols.

jaen11:12:47

Since multimethods are a superset of protocols in terms of dispatch.

niwinz11:12:23

of course but its perfromance is not as good as with protocols

niwinz11:12:59

so I think protocols is much better approach (as dunaj has done)

jaen11:12:20

Sure, but that's an optimisation concern more than anything, now that Clojure is at 1.8 (almost) then changing the shape of the API is considerably harder than investing in optimisations.

jaen11:12:49

And also I think multimethods can be optimised to be fairly performant, let me find that.

jaen11:12:28

http://www.stroustrup.com/multimethods.pdf - see the last page for performance. But it's probably true that it would be slower in Java, since single dispatch is built-in into the VM.

jaen11:12:37

But then again I imagine the degenerate case of single dispatch multimethod could be reduced to Java's virtual method call probably.

shriphani12:12:55

Hi, I have a couple of Maven dependencies using a variable for versioning ( ${foo.bar} ) - how do I express this in project.clj using leiningen? Best I could find is “LATEST” and that isn’t necessarily a good solution IMO.

jaen12:12:11

It sounds like it could be easily expressed with boot, but I'm not sure how to do it with lein.

shriphani12:12:11

@jaen: stuck with lein since it is what I know. Are there many boot projects in the wild? I have never seen one.

jaen12:12:36

There are some projects that use boot certainly - https://github.com/tolitius/mount, https://github.com/mjmeintjes/boot-react-native, https://github.com/Jannis/om-next-kanban-demo - but yeah, it's still less popular than leiningen

jaen12:12:55

Especially if you do not use Clojurescript

jaen12:12:03

Since it's where boot has most of it's edge over lein.

jaen12:12:53

I remember @seancorfield recently mentioning moving from lein to boot at work and being pleased.

jaen12:12:30

Also adzerk dogfoods boot in their projects - boot tasks, hoplon and such.

juhoteperi13:12:27

In addition to ClojureScript tooling I think another place where Boot has advantage is projects with multiple closely tied together artifacts, Boot allows one to write some tasks to build and deploy multiple artifacts from one build.boot: https://github.com/Deraen/less4clj/blob/master/build.boot#L57-L88

jaen13:12:57

So basically this outputs exact same jars just with different metadata?

juhoteperi13:12:10

No, the jars contain different files

jaen13:12:51

@juhoteperi: which part of the build decides what files go into the jar? I can't seem to find it from a quick glance.

juhoteperi13:12:45

@jaen: with-files uses a predicate to filter the fileset so that the wrapped tasks only see the selected files

jaen13:12:19

Oh, gotcha.

jcomplex14:12:45

just a quick intro, very new to Clojure coming from years of .NET and RoR web development. Tasked with building a C# .NET application as a Clojure website.

meow14:12:46

I've got this function I wrote and am wondering if there is some existing solution to this that is more idiomatic?

(defn hashmap-set
  [keyvals]
  (persistent!
    (reduce
      (fn [ret [k v]]
        (assoc! ret k (conj (get ret k #{}) v)))
      (transient {}) keyvals)))

meow14:12:36

Basically I want to end up with a map whose values are the set of all the values in the original keyvals for the same key.

meow14:12:04

So kind of like group-by.

jaen14:12:15

@jcomplex: out of curiosity - does "C# .NET application as a Clojure website" means you will be doing CLR Clojure or are you moving to JVM?

meow14:12:34

If not, is there a better name for this thing?

jcomplex14:12:42

@jaen moving to JVM. Essentially a port.

jcomplex14:12:41

@rhansen: thanks for the warm welcome

jaen14:12:03

I see. I thought you might have wanted to leverage the ability to share your C# code between Clojure CLR and the current application.

jaen14:12:13

But in the end moving over to JVM is probably a smarter move.

jaen14:12:27

The only big use of Clojure CLR I've seen is the Unity plugin that lets you use Clojure.

meow14:12:53

Wondering if I could replace that function using into {} xform and maybe a custom stateful transducer...

meow14:12:19

It just feels like I'm reinventing the wheel.

jcomplex14:12:50

Has anyone in the community used Monger?

jcomplex15:12:58

i like to write test driven code and would like to write a test for Monger and also I am trying to get metadata from gridfs

jcomplex15:12:31

but i notice they took out the connected method

rhansen15:12:57

@jcomplex: Can’t help you with that. Never used gridfs. Mostly used it as a json datastore, and for that monger worked perfectly.

jcomplex15:12:00

Ah yeah I can see that

jjconti15:12:36

why this is not a valid set? #{1 1}

jjconti15:12:51

i would expect to return #{1}

roberto15:12:50

haven’t used gridfs before, but have used monger

jcomplex15:12:42

I noticed there is not much documentation for the gridfs namespae on monger

jcomplex15:12:13

I guess I will need to try this out for all of us

kimsnj15:12:41

@jjconti: #{} is a reader macro that expects a valid set, you should use the set function for conversions (for some more reader macros: https://yobriefca.se/blog/2014/05/19/the-weird-and-wonderful-characters-of-clojure/)

staypufd16:12:25

Hello - I’m using Korma, but I need to be able to use the clojure.jdbc libs :row-fn capability in my query as well. I was wondering if anyone has a example of using it in the korma dsl syntax.

staypufd16:12:39

I have googled but haven’t found anything

meow16:12:36

@jjconti: I seem to recall that you cannot do that for set literals for some reason - can't remember why. But you can do (into #{} [1 1])

meow16:12:37

oops - @kimsnj had the answer

meow16:12:03

so (set [1 1]) is also valid

jjconti16:12:15

thanks kimsnj

mike_ananev16:12:15

Hi there! Does anybody knows how can I implement forEach cycle from Java 8? Context: I do much work with Apache Spark and there are a lot of examples on Scala or Java 8 where forEach method is used. https://github.com/apache/spark/blob/d83c2f9f0b08d6d5d369d9fae04cdb15448e7f0d/core/src/main/java/org/apache/spark/api/java/function/ForeachFunction.java

mike_ananev16:12:45

I need not reinvent similar cycle in clojure but call java 8 forEach from clojure. Thanks.

jcomplex18:12:07

this might be a basic question can you get the value from an atom that is defined in another namespace?

jaen18:12:36

Just like you can refer to a function or define in another namespace.

jaen18:12:45

Did you have any problems or just asking a priori?

roberto18:12:55

(require ‘other-ns :refer [my-atom])
(prn @my-atom)

jaen18:12:21

That looks as if you were derefing a namespace to me, could be confusing.

jcomplex18:12:30

just asking trying to understand the theory

roberto18:12:36

hehehe, yeah, you are right

roberto18:12:43

syntax error in the require

roberto18:12:36

more syntax error, but u get the gist

jaen18:12:17

Right. So to be exact - you don't really refer to atoms. (atom something) creates a value which is an reference type with initial value something. You then have to bind that value to something like (let [my-atom (atom something)] ...) or (def my-atom (atom something)).

jaen18:12:34

You then can refer to that name and dereference it - @my-atom.

jaen18:12:46

If you define your atom in another namespace then usual rules to refer to things from other namespaces apply. Atoms are no different from 123, "magic", {:a 12} or (fn [a] (* 2 a)) in that regard - they are just values that can be bound to names using let or def.

jaen18:12:06

I hope that makes sense?

seancorfield18:12:52

@jaen: Yes, so far our switch from Leiningen to Boot has been a big win /cc @shriphani

shriphani18:12:09

I see. good to know.

seancorfield18:12:08

I think you’ll start to see more projects with build.boot files — and possibly supporting both Leiningen and Boot.

seancorfield18:12:16

I’d like to see a boot-template ecosystem so I might take a shot at a Boot equivalent to lein new this week…

jaen18:12:38

Yeah, templates for boot would be awesome.

jaen18:12:47

Especially if they supported Rails-like generators.

roberto18:12:14

and cljr-refactor that works with boot simple_smile

roberto18:12:43

i depend too much on cljr-refactor, sad it doesn’t support boot.

seancorfield18:12:02

Doesn’t it? CIDER supports Boot now… I would have expected the refactorings to work on top of that without needing anything specific to change?

roberto18:12:54

cljr-refactor is not part of cider

roberto18:12:20

but, some of its features seem to be lein specific

roberto18:12:28

for example, adding cljr dependency to project file

roberto18:12:04

that one in particular

seancorfield18:12:30

Ah, yes, I’d forgotten just how much it can do these days. I don’t know how it would support that for Boot, given that dependencies can be built dynamically via Clojure code (indeed, we store ours in deps.edn so it can be edited and manipulated independently, because we also "pin" certain libraries to fixed versions — so we’ll "depend" on version x.y.z and the build script will replace that with the actual version we use).

seancorfield18:12:37

Part of the problem with Leiningen for us was how comparatively static the project.clj file was (you could escape evaluation in with ~ and we were already doing that in several places).

derwolfe20:12:18

Hi - I’m using a forward declaration for a private function and am curious; is there any need to tag the function as private inside of declare?

derwolfe20:12:43

it looks like it would just be adding the metadata to the declaration (via https://github.com/clojure/clojure/blob/clojure-1.7.0/src/clj/clojure/core.clj#L217), but I’m not sure simple_smile

mheld20:12:18

friend vs buddy — which is the preferred auth lib?

mheld20:12:25

or is there another that I’m unaware of?

rm20:12:22

buddy looks better for me

jaen21:12:22

I'm not sure if it's better or not

jaen21:12:28

But it's certainly simpler to grok

jaen21:12:34

I couldn't make head or tails of friend

jaen21:12:50

But I coudl quite easily add authentication with JWT using buddy.