Fork me on GitHub
#clojure
<
2019-06-10
>
henrik04:06:40

What's the point of (find x y) as opposed to (get x y). Is it vestigial?

the2bears04:06:36

'find' returns the map entry, 'get' returns the value.

the2bears04:06:56

So some overlap.

the2bears04:06:08

A bit of convenience I guess.

petterik05:06:16

find is useful when the value can be nil. I find it useful when I'm using if-let or if-some.

👍 3
misha05:06:54

is it

public Object invoke(Object obj, Object notFound) {
        return RT.get(obj, this, notFound);
    }
and 2 is notFound?

seancorfield06:06:51

@misha Yes, a symbol tries to look itself up in its first argument, and if that fails it returns the second argument:

user=> ('foo 42 13)
13

👌 1
isaac06:06:53

Does Clojure will auto add type hints on constructor? (.someObjFn (SomeObj.)) need write to (.someObjFn ^SomeObj (SomeObj.))?

Iwo Herka08:06:56

Hi, how is Clojure's memory footprint? Do you know of any resources on this topic?

didibus08:06:21

It isn't the greatest, not the worst 😛

didibus08:06:30

I'd say it is on the bigger size

didibus08:06:40

It normally trades memory for speed

didibus08:06:18

But that's mostly due to that the underlying JVM also defaults to trading memory for speed

didibus08:06:01

Though on top of that, Clojure tends to create more objects then your average Java program, and those have memory overhead.

Iwo Herka08:06:20

I suspected that, having some experience with the JVM. I was wondering how viable is running Clojure on small servers (e.g. via Digital Ocean).

Iwo Herka08:06:10

Past a certain project size it's not an issue, however it would be a shame to pass on the small projects just because JVM eats too much memory and client is not willing to accept costs of hosting.

vemv10:06:23

> and client is not willing to accept costs of hosting. this would be huge red flag. I would not work for a client that can't afford a pro-tier server that same kind of client could pay late (if ever), be contentious, whimsical, etc... all the freelancer nightmares 🙂

jumar14:06:10

Still, you should be able to run a simple app on a small server without issues.

didibus08:06:41

Well, one little secret of the JVM, is that it can be forced to use less memory with a JVM option

didibus08:06:57

But then, it will perform slower, obviously, as it has to garbage collect more often

Iwo Herka08:06:07

Wouldnt that risk OutOfMemoryException?

didibus08:06:42

Most Clojure additional memory foot print, from my experience are short lived objects. So lots of gen1 garbage. So I'd suspect it could run with a constrained JVM, but I've never did so myself

didibus08:06:07

Mostly, every function is an object

didibus08:06:26

That's the main culprit

didibus08:06:42

But they arn't needed past the function call

didibus08:06:54

It all depends honestly.

Iwo Herka08:06:53

Oh, cool, thanks.

didibus08:06:12

We normally run Clojure on 8GB or 16GB RAM servers

didibus09:06:37

I think an alternative is also to use ClojureScript with NodeJS. I believe NodeJS has a good enough memory footprint, but actually I have no idea how it fairs against the JVM.

Iwo Herka09:06:18

> We benchmarked a new Clojure microservice on a 512MB DigitalOcean droplet. It was handling ~4000k requests / second while consuming only 60% of the RAM. I think only 300 concurrent users, though. Still, that's not too shabby.

Iwo Herka09:06:23

Not bad at all.

didibus09:06:39

Its not as good as that, read a bit further, he got mixed up, real numbers are lower down 😛

Iwo Herka09:06:00

Yeah... Well, I think we will have to test it ourselves and find out the hard way.

1
jumar14:06:18

Definitely. There was a pretty recent related discussion a few days ago in this channel too

didibus09:06:33

Post back the results

Suni Masuno12:06:29

So what's the current community attitude towards point free?

tavistock12:06:46

is that using partial and comp in clojure?

Suni Masuno12:06:48

No named intermediate values is the formal definition. In practice it's a mix of partial the threads -> ->> comp and anonymous functions with just %

tavistock13:06:20

I feel as though often using partial is obscuring, I prefer to design my api to be easily threaded (eg seq functions take use last arg, data editing in first arg), comp can be alright (and necessary for performance in the case of transducers)

tavistock13:06:54

i came across this and while clever it would probably have weird edges and confuse people not familiar with it https://stackoverflow.com/a/18656907

tavistock13:06:10

and i assume currying is a non-starter bc clojure leverages varadic-ness to the hilt

Suni Masuno13:06:11

Though I bet that would make a variant of ramda's curry pretty straightforward... https://ramdajs.com/docs/#curry

tavistock13:06:59

that looks nice, i haven’t seen something like this i clojure before though, anon functions with are widely used and like 90% there, so i assume thats why we dont have them

tavistock13:06:47

im pretty sure the _ currying exists because rambda was around before js got arrow functions

vemv17:06:17

> Early in Clojure’s public existence, there was a fad for “point-free” programming, a kind of code golf without any local variables. [...] https://stuartsierra.com/2018/07/06/threading-with-style

alexmiller13:06:27

what's the point? ;)

4
Suni Masuno13:06:47

I ask because I came here with the (likely)mistaken assumption it was an explicit goal of the language and community, and am not so sure now I had that right.

alexmiller13:06:02

point-free is definitely not a goal of Clojure

mloughlin14:06:30

what's better about point free? naming intermediate values can be very useful 🤷

dpsutton14:06:09

sometimes. threading macros are nice because they elide naming the intermediate values. same thing with function composition. some intermediates have good names. some are not worth naming and having to name would be detrimental

Suni Masuno14:06:27

And I'm not so much asking which is ACTUALLY better or worse, I know my opinions on that predate my time with Clojure. I'm more asking, where is the clojure project and community on that issue overall? Divided maybe?

manutter5114:06:17

I would say mixed rather than divided. Sometimes I use threading/composition, sometimes I use let with intermediates.

rickmoynihan14:06:47

I don’t think the community is particularly divided. The language has partial and comp in core, because they’re good functions to have around. Likewise -> and ->> are nice to have too. We just don’t have currying or lazy evaluation by default, and don’t think point-free programming is an end in itself.

tavistock14:06:01

we also have soft conventions around intermediate var names like using coll, xs, ys, which helps with “pointed” programming

rickmoynihan15:06:01

(let [xs1 (range 10)
      xs2 (filter odd? xs2)
      xs3 (map str xs3)]
 xs3)

;; vs

(->> (range 10)
     (filter odd?)
     (map str))
I don’t think the difference between these is really about point-free vs pointed. It’s that the intermediate names xs1 xs2 and xs3, make things harder, as they don’t add any meaningful information, and would be a cause of bugs. If at a certain “checkpoint” in the transformation it clarifies things to have a name, then you should.

👍 1
rickmoynihan16:06:17

I agree you should design with argument orders in mind, and for -> and ->> but I don’t see that as being at odds with partial. I have no problem using partial, it has a clear meaning that can be used to communicate intent better than alternatives. Indeed I see it as another reason for considering arg order as important.

misha16:06:51

is there a (preferable) way to enforce function's signature, but keep it's implementation open? e.g. define multimethod with 1) no implementations, 2) and (somehow) no defined dispatch function, which would be supplied by user. Or would docstring be sufficient? "provide function with [x y] signature"

vemv17:06:24

Wouldn't defprotocol suffice?

rickmoynihan16:06:57

If you really want that — definterface with reify maybe?

noisesmith17:06:06

there's no reason you can't define a dispatch function that relies on runtime extension (or even an argument to the method itself)

misha20:06:16

I know I "can" and it is "doable", but should I? This will end up as public library API, so I'd prefer to minimize a) weird, and b) characters™ kappa

noisesmith17:06:23

it seems weird but it's definitely doable

noisesmith17:06:54

or a defmulti that uses another defmulti as its dispatch

Suni Masuno17:06:46

Does mapv count as evaluating the seq? AKA are things still lazy or would a mapv on an infinite list lock things up?

Alan Thompson17:06:05

mapv is not lazy

Suni Masuno17:06:00

So it is possible that the mapv I'm looking at, and confused by, is someone's clever way of making something evaluate in an environment where they fear mutation?

noisesmith17:06:16

often mapv is used inside with-open or otherwise inside a context where they want the lazy-seq to use a resource that will not be available when the block returns

Suni Masuno17:06:40

Well ain't that interesting. I was wondering why everything was in mapv all over the place here instead of just a bunch of maps with vec at the end

alexmiller17:06:20

mapv is a) takes and returns vectors so stays "in collections" b) is eager and c) due to prior can be useful in avoiding laziness effects

alexmiller17:06:53

these tradeoffs are also similar to transducer tradeoffs and indeed (into [] (map F) V) is similar

alexmiller17:06:56

that said, mapv is used a lot where people don't understand all that

alexmiller17:06:40

it's often hard to tell the difference between principled and wanton use of mapv :)

Suni Masuno17:06:48

Yeah, I'm having that moment, and I don't have access to the original people

alexmiller18:06:25

when I hear "a bunch of maps", that suggests you might be going through multiple mapv calls on the same data. in that case, using (into [] (comp (map F1) (map F2) (map F3)) V) is going to much more efficient than (->> V (mapv F1) (mapv F2) (mapv F3))

alexmiller18:06:00

in that the former will not create any intermediate vectors

CyberSapiens9718:06:45

guys, a quick one, just saw this on clojure documentation and in multiple libraries, what is a

Positional Factory Function
?

noisesmith18:06:41

it's a function that creates an instance of a specific class, and it takes positional arguments

noisesmith18:06:53

as opposed to a hash-map with keys for the slots

noisesmith18:06:13

(ins)user=> (dir user)
nil
(ins)user=> (defrecord Foo [x y])
user.Foo
(cmd)user=> (dir user)
->Foo
map->Foo
nil
(ins)user=> (= (->Foo 1 2) (map->Foo {:x 1 :y 2}))
true

noisesmith18:06:39

->Foo is a positional constructor function

alice19:06:31

What's the current state-of-the-art for rest apis and stuff? 2-3 years ago I wrote an app with Compojure, since then I've heard about yada & bidi, reitit, and some others. What should I pay attention to?

souenzzo19:06:36

#pedestal and #reitit (that uses pedestal) @alice

alice19:06:50

Thanks :thumbsup:

nha19:06:29

I prefer Yada over Pedestal, haven't used reitit though.

cupello21:06:12

Hi folks! Is there a way to define something like a var and a fn with the same name? Example: Executing my-fn-var outputs "Hello" and executing (my-fn-var) returns "world".

tavistock22:06:18

maybe not what you meant but maps and keywords (and more) are data structures that are also functions, they do this using IFn

👍 1
cupello22:06:56

Nice!!!! Thank you!

tavistock22:06:55

I am begging you not to do this but as an intellectual exercise here you go:

(ns my.playground)


(extend-type js/String
  IFn
  (-invoke 
    ([s]
    "world")))

(def my-fn-var "hello")

(prn my-fn-var)
(prn (my-fn-var))

cupello22:06:08

Good! Thanks!

didibus23:06:18

Not globally no, but locally you can shadow them if you don't need to use both

didibus23:06:30

(defn x [] ...)
(defn a [x]
   (* x 2)) ; This will be the argument x, not the fn x.

lnostdal21:06:54

not in Clojure ..if i understand you correctly (this is possible in a lisp-2 type language like Common Lisp tho)

👍 1