Fork me on GitHub
#beginners
<
2019-07-31
>
GC06:07:38

Hey, I am just wondering where clojure is used mainly, like python is good for data-science and backend, java is good for backend and mobile applications.

GC06:07:46

Where does clojure fits

henrik06:07:47

Clojure is pretty general purpose, but if I’d have to highlight something, I’d say it’s particularly good where the business problem is complex.

henrik06:07:09

I.e., the inherent, irreducible complexity of the domain or problem you’re working on. Simple problems might yield simple enough solutions in any language. But when things get complex, the efficiency multiplier of Clojure starts going up.

seancorfield06:07:54

@gagan.chohan According to http://blog.cognitect.com/blog/2017/1/31/clojure-2018-results the most popular area for Clojure is web development

Alex Miller (Clojure team)06:07:31

^^ I think that reflects the distribution of the industry more than the distribution of Clojure, which is general purpose enough that someone is using it for anything you can think of

Grigory Shepelev06:07:54

Good day! I started learning clojure from haskell. I practice on CodingGame or HackerRank. And can't understand how compiling works. They have a template for a task:

;; 
(ns Player
  (:gen-class))
; The while loop represents the game.
; Each iteration represents a turn of the game
; where you are given inputs (the heights of the mountains)
; and where you have to print an output (the index of the mountain to fire on)
; The inputs you are given are automatically updated according to your last actions.
(defn -main [& args]
  (while true
    (loop [i 8]
      (when (> i 0)
        (let [mountainH (read)]
          ; mountainH: represents the height of one mountain.
        (recur (dec i)))))
    ; (binding [*out* *err*]
    ;   (println "Debug messages..."))
    ; The index of the mountain to fire on.
    (println "4")))

David Pham07:07:34

You could write a function in your current project that solves your problem and copy paste it in the solver in Codewars?

Grigory Shepelev07:07:02

No. It has to have main and namespace given in the template. I can't understand this part.

Grigory Shepelev07:07:20

How do I repl with main and namespaces.

David Pham07:07:50

Can you start a repl?

magthe07:07:52

Do you use a particular editor to write your Clojure code?

David Pham07:07:00

Try to start an init project and solve the problem in a isolate environment. Once you wrote a function that solves it, copy paste it back to code editor in your web browser and in the -main function call the function you wrote

Grigory Shepelev07:07:31

I want to understand the java interop, namespaces and main function in clojure.

Grigory Shepelev07:07:41

Besides solving a task.

Grigory Shepelev07:07:24

I tried to call

clj -m Player task.clj
But got a namespace error

David Pham09:07:08

I don't know how you can solve this with clj, but if you use lein, you could try to start a project and there develop locally with a repl

noisesmith17:07:28

Player is a weird name for a namespace (there's issues with single-segment), but if Player.clj is src/Player.clj then clj should find it

Grigory Shepelev06:07:34

How do I run it in REPL on my machine? I don't know how to deal with main and namespaces

David Pham07:07:06

I am trying to solve the following problem in clojurescrirpt. I would like to import a namespace foo in my current one which contains the var-1,..., var-n variables. How can I reference them dynamically in my current namespace?

henrik09:07:37

Dynamically? The idiomatic way to go is to reference my-namespace/var-1 etc. as needed, so as to make it obvious that they’re coming from another namespace, and not unwittingly introduce naming conflicts. If you want to reference a batch of data in one go, it might be better to use a map containing the composite data rather than splitting it up.

Mno08:07:54

I know it's probably not what you want but :refer :all?

David Pham09:07:04

@hobosarefriends I don't think this is even allowed in clojurescript lol

Mno09:07:52

oh my bad, clojurescript isn't my strong suit, I assumed that would work.

David Pham09:07:30

haha, no problem, thanks for trying! Clojure is really cool so I love it

❤️ 4
jakuzure10:07:35

not really a cljs question, just wondering if stuff like this would be possible in js theoretically, or do you just have to write it out 3 times?

danielneal10:07:32

I think that stuff is possible in react too, there’s libs that will let you map a function over a collection in pretty much the same way

jakuzure10:07:05

good to know, thanks!

wagner leonardi15:07:06

Hi guys. I'm comming from Node.js (where we are used to set every IO task async by default) and I'm having some trouble to understand promise and clojure.async. I just talked with some friends that work in big companies with Clojure and they mostly don't even care to do async and they're fine with blocking IO. I just did a small test with only 10 messages (each blocks for 0.5~): sync code runs in 6.5sec while async runs in 2.7, it's quite impressive to me to just ignore that. I just placed (future with a callback function where blocking IO happens to achieve that - brief test explanation: https://github.com/plygrynd-jynkyrd/clojure-async/tree/master#clojure-async-test - future function w/ callback: https://github.com/plygrynd-jynkyrd/clojure-async/blob/master/consumer/src/consumer/core.clj#L5 My questions: - Do the clojure community and clojurians don't really care much about making every blocking IO async? - Is okay to stick only with (future to achieve non-blocking IO , and ignore core.async? - Is the knowledge of core.async important to work as Clojure programmer?

hiredman15:07:16

Future isn't non-blocking io

hiredman16:07:42

Clojure and clojurescript are very different

Crispin16:07:51

each future is a thread. core.async, on clojure, can be implemented with threads (using thread) or without threads (using go) or a combination (each end of a channel can be different). so depends what you are doing.

hiredman16:07:31

Clojurescript runs on JavaScript so it is just like Js it is a single threaded runtime

Crispin16:07:39

Im not sure why you are using callbacks at all

hiredman16:07:19

clojure on the jvm has the advantage of a very good multithreaded runtime, which can run a thread count which is often shocking to people used to node's forced single thread just fine

hiredman16:07:14

and when you have a real multithreaded runtime, it is often not a big deal to block a thread for any reason (io, locks, etc), because blocking that thread doesn't impede progress of other threads

hiredman16:07:40

benchmark wise, I would be deeply skeptical of benchmarks written when you are just learning the language

Boaz Blake16:07:21

Hey everyone - learning clojure and I am wondering why dec x returns a different value from - 1 x? thank you!

(	defn internal-growth-rate [ income assets divis ]
	(let 
    [ dividend-ratio (/ divis income)
      b (- 1 dividend-ratio)
      roa (/ income assets)
    ] 
  ( / (* roa b) (- 1 (* roa b)) )))
  
(internal-growth-rate 100000 400000 20000) ; answer should be 1/4
(	defn internal-growth-rate [ income assets divis ]
	(let 
    [ dividend-ratio (/ divis income)
      b (dec dividend-ratio)
      roa (/ income assets)
    ] 
  ( / (* roa b) (- 1 (* roa b)) )))
  
(internal-growth-rate 100000 400000 20000) ; answer should be -1/6

Crispin16:07:40

(- 1 x) is 1-x

Crispin16:07:48

(dec x) is x-1

Crispin16:07:10

you've rolled your own using java interop. Maybe look at some existing servers. I use immutant myself. But there are a few choices. https://github.com/ptaoussanis/clojure-web-server-benchmarks

wagner leonardi16:07:40

@hiredman I'm talking about Clojure really, so I wouldn't call "non-blocking IO" but "my app doesn't stop for IO and continue receiving requests", that was I'm trying to achieve and it worked doing (future. @crispin it was on purpose, I wanted to use wrap blocking calls (such HTTP or JDBC), that's what I did: - Received 10 messages from A - For each message an HTTP request to B (I used future here) - After B response, I also notify A , that's why I used a callback

wagner leonardi16:07:43

but anyways, is learning core.async mandatory .. and clojure community doesn't really care much to do every IO async?

Crispin16:07:21

it is not mandatory. its an add on library after all.

Crispin16:07:09

clojure has an inbuilt threadpool.

Crispin16:07:55

you can write naive code and have it magically multithreaded without doing anything

hiredman16:07:48

it isn't the clojure community, it is the programming community at large outside of javascript

hiredman16:07:17

javascript has a very odd runtime environment

hiredman16:07:56

and the js community instead of viewing it as a lamentable limitation, has decided it is the best, which means people who learn this stuff while writing js have a hard time recovering when they encounter runtimes with multithreading

hiredman16:07:58

"he took a node to the dome and never recovered"

wagner leonardi16:07:39

@crispin such as.. I did with (future ? or it was OK? I'm just worried to apply to an Clojure job and not pass due not knowing clojure.async or that (future solution is "too ugly"

Crispin16:07:48

Where I use core.async is to bring some sanity back to the browser.

Crispin16:07:18

if you are beginning, you can leave core.async aside until you've learnt clojure

Crispin16:07:47

just be aware future spawns a thread. That may even be overkill.

Crispin16:07:12

Try and just use plain clojure, and then watch it run and how it uses your cores. you may be surprised.

wagner leonardi16:07:42

@crispin actually I'm quite proficient in clojure "plain" already, I just don't have professional experience and knowledge to deal with these kind of particular issues already. When I used "plain" clojure with those 10 0.5sec messages.. it got 4 seconds more than" (future clojure", for 100 messages more than 50sec!! the problem is knowledge to deal with block IO, thanks for helping me 🙂

Crispin16:07:44

idiomatic clojure would deref the future to get the resulkt, not call a callback

wagner leonardi16:07:12

@crispin the problem is deref will block my app untill the response (without listening to other requests!)

Crispin16:07:53

because the answer is not ready yet. what else can it do?

hiredman16:07:55

if only you had another thread to listen for requests

wagner leonardi16:07:26

@crispin listen to other requests incoming.

Crispin16:07:56

btw, you can check the status of the future with future-done?

Crispin16:07:10

that is non blocking

👍 4
wagner leonardi16:07:50

@hiredman yes, that was I achieved with (future , I don't know if it's the best solution though

Crispin16:07:59

you should read up on posix and server programming

Crispin16:07:24

you would use something like select or epoll in a single listening thread to find out whats ready

Crispin16:07:55

but theres no need to. the servers are already written for you

hiredman16:07:25

you shouldn't need a callback in that case

Ahmed Hassan16:07:54

For non blocking IO you can consider Aleph.

hiredman16:07:14

the general pattern for multithreaded servers is you have a thread accepting connections, when a connection is received the connection is handed off to another thread

ghadi16:07:27

Fibers for the JVM are coming soon enough, too.

hiredman16:07:28

so there is no need for a callback or communicating back to the original thread

Crispin16:07:39

(as an aside, in core.async the equivilent construct to select is alt!)

ghadi16:07:49

fibers in project loom will make all blocking calls to I/O suspendable

hiredman16:07:57

you can also do all the single threaded event loop stuff on the jvm too

Crispin16:07:19

@ghadi when do they land in the JVM?

wagner leonardi16:07:26

@hiredman yeah, you're right, I think that I only did that callback to ensure that I was waiting to finish (and compute how long it took), thanks

ghadi16:07:28

single threaded event loop stuff, as well as async/await, have large costs in the user facing programming model

ghadi16:07:42

async/await is widely considered to be a v.1 technology

hiredman16:07:03

but the multithread stuff is more straightforward and doesn't chop your code up in to callbacks

👍 4
ghadi16:07:17

@crispin no date commitments, but it's progressing

ghadi16:07:34

The demos at JVMLS a couple days ago were :thumbsup::skin-tone-4:

markmarkmark16:07:47

that reminds me that I need to check on the JVMLS videos

danielneal16:07:09

@ghadi what’s the alternative to async/await - the v.2 technology?

ghadi16:07:19

just write sequential blocking code

ghadi16:07:22

like in go

ghadi16:07:36

the runtime does the magic suspension, totally transparent to the user

Crispin16:07:48

so is the JVM going to give the BEAM a run for its money? 😍

ghadi16:07:08

we had a conversation yesterday about how people who learn async/await need to unlearn it

ghadi16:07:24

it's harder to understand how simple fibers are, when you know async/await

Crispin16:07:40

"async/await is the one night stand of concurrency primatives"

hiredman16:07:26

for example https://gist.github.com/hiredman/9a086f7b34f8d4fc3f95a251a616bafd is a little websocket chat app that uses a single threaded event loop and callbacks, and it is a mess (some because of the callbacks and some because of java.nio)

wagner leonardi16:07:47

@crispin I think I got what you mean, I just don't get the "problem" of having an app where the main thread to listen to the requests.. and dispatch each request action (where blocks IO) to another thread to continue receiving more calls I'm not just secure if that (future is an acceptable solution for that for a job apply, could you suggest me a better solution? (aside libs, I really want that knowledge how to deal with blocking IO in clojure)

wagner leonardi16:07:47

@hiredman indeed!! That's why I started to learn core.async to have a better solution. Not comparing apple and bananas, but it's pretty straightfoward doing async with Node.js Promises, just got confused to achieve the same with Clojure

Crispin16:07:37

if you are familiar with promises, then core.async you should learn.

Crispin16:07:28

promises are really glorified callbacks. core.async is proper "inversion of control" and allows you to write top down "single threaded" code that is broken up into a state machine for you by the go macro

Crispin16:07:18

the best way, imho, to learn core.async is to do it. I never got it by reading. I had to work with it to get it.

✔️ 4
hiredman16:07:37

core.async can help eliminate callback soup, if you are using a library/framework where you would have callback soup

Crispin16:07:49

when I first watched Riches launch talk, I was lost. But after grappling with it and learning by doing, I went back and watched, and everything made sense

hiredman16:07:19

but if you are not using such a library, it is not natural to have callback soup on the jvm, so using core.async can be weird

Crispin16:07:21

So in your hypothetical server, you can receive something from the network and just stuff it on a channel and then get the next.

hiredman16:07:32

core.async is also two parts: channels and go blocks

Crispin16:07:44

then something else can pull from that channel in a blocking context

hiredman16:07:59

channels are useful with real threads as well

Crispin16:07:44

load that up in your editor and begin evaluating

markmarkmark16:07:11

@leonardiwagner in your specific example, you could probably pass an Executor/ThreadPool to the HttpServer in its setExecutor method and the handler will just be called on those threads automatically

👍 4
wagner leonardi16:07:39

thank you! I'm gonna try that 😄

wagner leonardi16:07:53

@hiredman @crispin thank you so much guys! I'm much more comfortable now, I'm going practice more What is really different to me, is because reading most of clojure.async stuff that I found, they most use deref (which blocks the application untill the completion). While in Node.js, at each promise completion I got a callback to do whatever I want with the result without blocking the app.

wagner leonardi16:07:34

@crispin Thanks, I'm gonna watch that talk right now

Crispin16:07:17

well, go returns a channel and doesn't block. and the channel will have the final form evaluation pushed down it when done... but thats getting way ahead of where you are. enjoy the talk

wagner leonardi16:07:37

@crispin I'm gonna try that as well, thanks! sorry to be repetitive, but last question. Was the (future solution that I did "bad" in a level that could fail a job apply?

Crispin16:07:03

I don't want to be rude, but if I was hiring, it'd be a "no" from me. But you are on your way. Keep going. It will all come together with more experience.

wagner leonardi16:07:46

@crispin thanks! I really appreciate your help and your time, thank you 😄

markmarkmark16:07:59

if you like promises, then CompletableFuture in Java might be worth looking into

markmarkmark16:07:10

it isn't super nice to use from Clojure, but it's not too bad

wagner leonardi16:07:08

haha that's what I suppose. I'm just trying to figure out the "clojurian way to solve problems", that's quite hard without working with other professionals but that's kind of help that I need, thank you!

markmarkmark16:07:14

generally speaking, "The Clojure Way" is the same as "The Java Way" in many instances.

markmarkmark16:07:43

Java interop is idiomatic and expected. Just because Clojure core doesn't have something explicitly built in doesn't mean it isn't idiomatic.

seancorfield18:07:07

If you want something that provides a very thin layer of "syntactic sugar" over Java's CompletableFuture, take a look at https://github.com/worldsingles/commons (disclaimer: it's my code).

wagner leonardi01:08:25

thank you! I'm gonna check it!

Ashley Smith20:07:17

This isn't really a clojure question but its only a quick one: I'm making a web app and I'm going to start sending data from my server to my app (posts, members etc). What is the best practice for this: A: Poll the entire state and then only poll again on refresh or whatever. I can't see this one being a good idea as that's a lot of data that may not be used B: Only poll the data required for the current page. I feel like this is the answer but can't be sure?

jaihindhreddy02:08:29

Usually in apps where communication b/w frontend and backend is some sort of RESTful APIs over HTTP, there is a lot of parochiality in creating more and more resources that are tailor-fitted to fetch just the right data for a specific use case (page/component) on the frontend. An alternative is to make the backend expose it's data with a schema allowing the frontend to query what it wants. This reduces endpoint-parochiality. Checkout GraphQL (popular in JS land), and fulcro and/or pathom in Clojure(Script) land for this approach.

noisesmith20:07:26

that's a big subject with a lot of alternatives, and the answer changes for different styles of pages

noisesmith20:07:53

for an old school plain web page, just polling the data for the current page is the obvious choice, for modern "web app" situations, not only do you want to send extra context / data to make other views / transitions responsive, but you also want to be able to push updates ass applicable to the clients from the server (other user statuses, change in state of domain objects that user has some stake in...)

Ashley Smith20:07:42

yeah, thats kind of where I'm at. I'm trying to think of the best approach to start you know? As a beginner it is a little daunting

noisesmith20:07:02

if this is your first time doing client/server web stuff, start with the old school version I think, then you can look at incorporating ajax or websockets etc. if you need the features / behavior or get curious

SgtZdog20:07:41

Having done a little ajax, it doesn't make your life easier, unless that's what you actually need. So if you don't need to do real time page changes, don't, let your page changes be queries up to the server and just reload the page.

eskemojoe00720:07:54

In my repl, I struggle to actually run code while in the Luminus template. I run (start) from the user ns, but when I try to access any code I'm writing, such as things in the routes I just get No such var: proj.routes.auth/func. I'm going crazy. What am I doing wrong?

noisesmith20:07:41

often that No such var, when you know the file defines a var of that name, means that there was an error in loading the ns that got swallowed or hidden in output spam

noisesmith20:07:12

try (require 'proj.route.auth :reload) and if you see an error message look at *e to see the full back trace of the error

eskemojoe00720:07:34

That worked...

noisesmith20:07:24

just curious, did it show you the real error, or did it fix the error?

eskemojoe00720:07:34

fixed the error.

SgtZdog20:07:59

With that said, you should still use partials/partial pages. The modularity makes the design process go much faster and can make changing to something that like a web app or ajax driven approach easier.

SgtZdog20:07:59

If you try running the value instead of as a function call does it spit back an error? (So instead of doing (myfunc) do myfunc)

jplaza20:07:42

Hi! Still wrapping my head around namespaced keywords for map keys. Can somebody give an example of how one would benefit from using them?

{:com.example.product/id 1029
 :com.example.product/price 10.5
 :com.example.product/name "Super Shoes"
 :com.example.product/category {:com.example.category/name "Shoes"}}

VS

{:id 1029
 :price 10.5
 :name "Super Shoes"
 :category {:name "Shoes"}}
For example

SgtZdog20:07:04

I too am interested, as the only I can think of is explicit declaration of where a thing lives.

noisesmith20:07:31

@jplaza {:tree/bark false :dog/bark true}

noisesmith20:07:58

in the dog ns it's just ::bark and it gets the right one naturally

noisesmith20:07:41

@jplaza more generally, this lets you combine data from various sources without having to audit for clashes, or wondering where everything came from

noisesmith20:07:59

this is particularly interesting when specifying a mapping from a key to a data constraint (eg. spec)

👍 4
eraad20:07:21

@noisesmith Would the idiomatic use of namespaces be to communicate the structure of the information (ie :dog/barks) or the structure of the program (program.ns.dog/bark)?

noisesmith20:07:40

you can know that a :customer.record/id and a :vendor.account/id are different things, with different constraints, without every line of code being 300 characters long

noisesmith20:07:43

ideally the information structure and program structure share some commonality, in practice namespaced keywords are useful for both

jplaza20:07:26

@noisesmith so NS are actually useful for development more than for the structure of the data. For instance, how would you translate the example you gave to a JSON representation?

{:customer.record/id 12
 :vendor.account/id 1007}

;; JSON

{"customer_record": {"id": 12}
 "vendor_account" {"id": 1007}}

;; or like this
{"customer_record_id": 12
 "vendor_account_id": 1007}

jaihindhreddy03:08:01

Namespaces are about precision in the semantics of names. Inside a program, the names don't matter (most of the time). We often have no names using positional args instead. But in the context of building a service, or a cog in a system, the names suddenly are scoped to the organization, or more often global. Service A's :playmight be completely different from service B's :play. So we use :A/play and :B/play. In fact, some other company might have a thing that has the name A. And this is why the reverse DNS names are used by convention. So you would use :com.mycompany.A/play and :com.mycompany.B/play. These are strong names and play well with other data without requiring context.

jaihindhreddy03:08:16

Watch Rich Hickey's talk "Language of the System" for more on this.

jaihindhreddy03:08:35

Excuse me if I misunderstood your question. If you were asking how to translate these semantics to JSON, then my answer is, you can't. JSON doesn't even have a name type. You can use transit, but it's still not just JSON.

jplaza03:08:42

Yes that was actually my main doubt. Thanks for the long response @U883WCP5Z! All the benefits you get when using namespaced keywords are palpable inside Clojure

jplaza03:08:24

Even if using Transit, having dict keywords of the kind of Keyword("com.mycompany.A/play") say in Python feel kind of weird

jaihindhreddy03:08:27

No problem! These ideas are useful anywhere but unfortunately are embraced fully only in Clojure. We must encourage others to use these things.

jaihindhreddy03:08:28

Exactly. It's unergonomic in most other langs to use these things, but that's not the fault of these ideas. As an example, the Java code underneath Clojure is not very idiomatic. Doesn't mean it's bad.

jplaza03:08:37

Good point! It’s hard to let go idiomatic expressions, at least for me haha

4
noisesmith20:07:27

I'd prefer the latter (but neither cheshire nor clojure.data.json has either behavior out of the box)

noisesmith20:07:30

cheshire just drops the namespace (so one id overwrites the other), data.json puts the / in the key directly

lilactown20:07:12

i personally like having / in the key but I understand that it doesn't match idiomatic JSON

jplaza20:07:19

So it looks like ns keys are useful only inside Clojure

bringe22:07:35

Hi. I have a question that's not exactly specific to clojure, but a clojure context may be helpful for me. Is there a real difference between a linter and a formatter? Looking particularly and joker and cljfmt. Joker seems not to be concerned as much with formatting, but more with use of undeclared vars or empty let forms, etc. So if we wanted something for our team to use that would help make sure our code conforms to a similar style, I guess cljfmt would be the way to go? But then where does that leave linting? Are linters and formatters meant to be used together? Do they sometimes come packaged together? Is there a blurred line between the two? Not looking for answers necessarily to ever one of those questions but wanted to illustrate my thoughts. If anyone can shed some light that would be appreciated.

ghadi22:07:25

generally linters do semantic analysis but formatters only look at syntax

seancorfield23:07:54

@brandon.ringe Linters often spot (potential) bugs in your code by pointing out "unusual" constructs, from a stylistic/semantic point of view, as well as spotting a lot of unused/unneeded things in your code. They can have great value on their own.

seancorfield23:07:49

I don't find formatters to be much use because they nearly always reformat parts of my code in ways I don't like. And I don't mind slight differences in source formatting across team members (consistency within a single file is worth suggesting). Mostly, with Clojure, you can just let your editor take care of general indentations and just encourage team members to follow a few simple conventions.

seancorfield23:07:34

In other languages, brace style and tabs/indentation can vary wildly between teams, so opinionated formatters can be very useful 🙂

bringe23:07:40

I see. Thanks!