Fork me on GitHub
#beginners
<
2018-05-11
>
Alex Miller (Clojure team)00:05:50

The Clojure Applied book has a lot of material on using core.async

kaffein10:05:53

hi people, just a newbie question about Clojurescript : I'm not a front-end developer (I mean not at all) but somehow I would like to give clojurescript a shot to get in. Do I have to be good in JS already or is it okay to just dive in CLJS right away ?

gklijs10:05:59

@kaffein depends a bit on what you want to do, a bit ok knowledge about JS in general can come in handy, but is not really needed. I’m no front-ender myself, but using re-frame combined a css-framework like bootstrap or bulma makes it easy to do front-end without knowing much about either JS or css.

tstelzer10:05:36

i guess thats the same for any language / host platform relationship no?

tstelzer10:05:41

or most at least

tstelzer10:05:57

elixir / erlang, clojure / jvm, clojurescript / nodejs

tstelzer10:05:20

i assume there is a brick wall you may hit at some point, if you don't familiarize yourself with the host platform

kaffein10:05:26

@gklijs let's say that i know js but I'm not an expert 😉

kaffein10:05:49

But I got what you mean

kaffein10:05:21

@wushee ok ok I understand

gklijs10:05:51

@kaffein that’s fine then, neither am I. Sometimes it come sin handy to know your way around the chrome debug tools, of which a large part is unknown to me.

kaffein10:05:28

Well I will probably have to start slowly then but I'd have to be ready for a little more on the JS side in the future

kaffein10:05:19

Thanks for your help guys

joaohgomes14:05:57

Hey guys, is there an easy way to, given a map with namespaced keys and given a specific namespace, create a view of this map with all keys related to supplied namespace? Like so:

(filter-namespace {:project/name "Proj Name" :project/id 1 :person/name "Joao Gomes" :person/id 1} :person)
{:person/id 1 :person/name "Joao Gomes")

dpsutton14:05:52

(namespace :namespace.of/key) ;; => "namespace.of" might get you started

👍 4
dpsutton14:05:16

(defn select-ns [n-s m]
  (let [target (name n-s)]
   (into {}
         (filter #(= target (namespace (first %))))
         m)))
(select-ns :a {:a/b 3 :a/c 4 :d 7})
#:a{:b 3, :c 4}

joaohgomes14:05:35

thanks again 🙂 @dpsutton!

👍 4
itsalitee14:05:44

hi everyone, what’s the best book/way to learn Clojure if you would like to do scientific computing with it? Also, has there been a valid benchmark of Clojure against other languages? thank you in advance.

dpsutton14:05:20

are you looking to learn clojure from the start or do you know clojure and want to apply it to scientific computing?

itsalitee14:05:11

I am looking to start clojure from the start, have very limited knowledge of it now. But I do want to apply it to scientific computing because of all good things I have read about it.

alan14:05:02

@ali417 subscribe to #data-science as well

itsalitee14:05:02

thank you for this! 🙂

alan14:05:37

No problem, I have your same issues and I'm trying to spur a discussion around the topic simple_smile

itsalitee15:05:30

yeah, there seems to be a lot of potential with this language but there is not an easy way to get mastery in it. Which is fine, just a not a lot out there like python, c++, etc!

alan15:05:35

Yeah, on #data-science we were talking about the tooling, and there isn't much available

👍 4
dpsutton14:05:18

my two favorite books are clojure for the brave and true and programming clojure third edition. the former is available for free online and available for purchase. the latter is by alex miller and on prag prog

itsalitee14:05:06

Thank you for your suggestions @dpsutton 🙂

dpsutton14:05:32

I would learn the language and how it works and then look into what you want. Immutability and functional paradigm can take a bit of adjustment to internalize how the language likes to work. And then work on whatever you want :)

itsalitee15:05:38

True, there is no shortcut in learning and that’s the plan @dpsutton, thank you!

joaohgomes19:05:11

I would also take a look at the http://4clojure.com site. You can learn by doing exercises and also by seeing the other developers solutions.

Vincent Cantin16:05:44

What mutable data should we use in a stateful transducer if we feel that we do not necessary need a volatile data? (that volatile: https://github.com/clojure/clojure/blob/clojure-1.9.0/src/jvm/clojure/lang/Volatile.java#L15)

reborg16:05:26

@vincent.cantin I believe volatile is there mainly to propagate changes to multiple threads in a core.async pipeline context (and tangentially perf). If you plan to never use it in there, you could go atoms. (Perhaps @alexmiller could confirm). But what's wrong with the volatile though?

Vincent Cantin16:05:54

I thought that atoms were doing more than volatiles.

ghadi16:05:11

volatile is non-atomic

ghadi16:05:39

it's just for publishing across threads. no guarantee of atomicity

Vincent Cantin16:05:16

Is there a variant of volatile without the Java "volatile" attribute that can be used from Clojure? Something like a pure wrapper of an Object with just its init and reset functions?

ghadi16:05:47

I don't follow

Vincent Cantin16:05:03

Let's suppose that I design some kind of stateful transducers which I know will only be used by the same thread. What (efficient) mutable data type should I use in Clojure?

reborg16:05:25

volatile is one of the cheapest thing in single thread context https://stackoverflow.com/questions/4633866/is-volatile-expensive

leonoel16:05:38

@vincent.cantin your options are : - a plain old unsynchronized mutable java collection - an array - a custom deftype with :unsynchronized-mutable fields implementing clojure.lang.IFn - use an external library to get your variables back

ghadi16:05:39

@vincent.cantin The advice I'd broadcast in this channel is to pretend that volatile doesn't exist. That being said, volatile is pretty much atom minus the atomicity guarantee during swap

4
ghadi16:05:40

> a plain old unsynchronized mutable java collection this doesn't use clojure equality semantics, fyi. If you use a map or set you may be surprised.

ghadi16:05:21

until someone gives me a hard SLA i don't let performance concerns win over clear code

leonoel16:05:48

for this use case it's perfectly legitimate

leonoel16:05:33

the question was explicitly about performance btw

Vincent Cantin16:05:35

@reborg @ghadi Thank you for your answer, it seems that volatile should not be a huge concern. However, since I am curious, I would still be very happy to know if there is something faster, even slightly.

mikerod18:05:53

You could do a one-off “mutable box” of your own @vincent.cantin

mikerod18:05:41

Just if you’re curious, something like:

(defprotocol IMutable
  (set-it! [this value])
  (get-it [this]))

(deftype MutableBox [^:unsynchronized-mutable holder]
  IMutable
  (set-it! [this value]
    (set! holder value))
  (get-it [this]
    holder))

👍 4
mikerod18:05:50

Not something I’d typically recommend doing if not needed though

mikerod18:05:05

that’d be a mutable field in with the semantics of a typical Java mutable field

mikerod18:05:24

with all the concurrency problems that comes with

Vincent Cantin07:05:55

I am wondering if (set! holder value) is fast or not. Do you know if this is the implementation of set! ? https://github.com/clojure/clojure/blob/clojure-1.9.0/src/jvm/clojure/lang/Var.java#L214

mikerod13:05:13

No. That’s for a var. set! Is a special form. It’s implemented in the compiler in Java. Pretty sure it should be about the same bytecode as = assignment in Java.

👍 4
mikerod13:05:39

@vincent.cantin I’m on phone GitHub which is annoying. But look at https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java look up the AssignExpr static inner class

mikerod13:05:16

Also you can checkout the InstanceFieldExpr looking at evalAssign and emitAssign impl here for an example like I showed you above. emitAssign you’ll see ends up as a putField eventually which relates to that bytecode.

Vincent Cantin13:05:41

Thank you ! I am going to read more.

mikerod20:05:47

@vincent.cantin I’ll add that emitAssign would be the path taken in cases where you are calling set! in a pre-compiled context, like a fn body (typical). The evalAssign, which is slower, should pretty much only happen if doing some runtime eval and/or like doing (set! <instance field here> 10) in the repl

Vincent Cantin16:05:08

I am not sur if set! could be used for local variables, the documentation for it is not clear to me. I will give it a try tomorrow.https://clojure.org/reference/vars#set

Appo721:05:53

hi, why do functions in a call like map foo bar not need to be quoted? (i.e map 'foo bar)

Alex Miller (Clojure team)21:05:18

foo is a symbol, it’s evaluated to find the function instance which is passed to map

Alex Miller (Clojure team)21:05:31

you want it to be evaluated, so it’s not quoted

Appo721:05:21

but wouldn't I need to quote it in common lisp? Sorry if I'm confused, new to the lisp world

bronsa21:05:11

common lisp is a lisp-2

bronsa21:05:13

clojure isn't

bronsa21:05:27

it means that common lisp has 2 namespaces, one for variables and one for functions

bronsa21:05:36

clojure has just one namespace, for "values"

bronsa21:05:14

in common lisp you'd need to actually do (lambda (x) (foo x)), #'foo is just a reader macro for doing that

bronsa21:05:23

#' in clojure means a totally different thing

Appo721:05:53

okay, wasn't aware of that distinction. That makes sense

bronsa21:05:54

sometimes common lisp is also less restrictive than the standard and just 'foo works too, but that's often just undefined behaviour

bronsa21:05:59

there should be a page in http://clojure.org with differences between clojure and other lisps fyi

Appo721:05:50

found it, thanks a lot!

Michael Fiano22:05:43

Common Lisp has 7 namespaces

Michael Fiano22:05:09

1) functions, 2) lexical variables, 3) special variables (distinct from the lexical variable namespace), 4) types, 5) goto labels, 6) block names, 7) quoted expressions containing symbols

Michael Fiano22:05:28

You can have the same symbol for 7 entirely different things.

Michael Fiano22:05:55

@bronsa Also that's not correct, about being undefined behavior. It is clearly defined what the difference is between 'foo and #'foo

bronsa22:05:17

I was giving an oversimplified version of lisp-2

Michael Fiano22:05:35

There is no undefined behavior in that regard

bronsa22:05:17

re 'foo vs #'foo, some lisps accept (mapcar '1+ '(1 2 3))

bronsa22:05:28

that's what I was referring to

bronsa22:05:42

it's not correct, some lisps accept it anyway

Michael Fiano22:05:48

When you call a function, you supply a function designator. The language defines a regular symbol to refer to the function of the same name in the global environment. A function, denoted by either #'func or its expansion of (function func), refers to the function of that name that is searched for starting in the current scope and working outward.

Michael Fiano22:05:25

CL-USER> (foo) "inner" "outer"

bronsa22:05:08

ok, I stand corrected then

Michael Fiano22:05:28

Sure 🙂 I'm still learning Clojure, but I have been using CL for a decade

bronsa22:05:38

and I haven't used CL in almost a decade :)

Appo723:05:58

thanks, so just so that I'm sure I have understood it, if I call map foo in common lisp, then foo is interpreted as a variable and 'foo refers to the function, whereas clojure lacks that distinction? If I got that right, how does clojure determine the difference?

bronsa23:05:08

it doesn't

bronsa23:05:12

clojure has no distinction

bronsa23:05:32

you can't have a variable called foo AND a function called foo at the same time

Michael Fiano23:05:57

map in Common Lisp is something else entirely. Clojure's map is like Common Lisp's mapcar.

bronsa23:05:01

clojure only has vars for global symbols and local bindings for local ones, vars and locals can hold any type of value, be it an integer or a function, local bindings can shadow vars

Michael Fiano23:05:12

and you cannot call (map foo ..) unless foo is a symbol whose variable points to a function object. Typically you'd do (mapcar 'foo ...) or (mapcar #'foo ...)

andy.fingerhut23:05:17

Example of shadowing in a Lisp-1 like Clojure that you would not find in Common Lisp: (defn f [x] (let [+ -] (+ x x))) then (f 2) returns 0, not 4. You are unlikely to write that particular example by accident, but shadowing names of Clojure functions like list and map is easier to do accidentally.

andy.fingerhut23:05:53

The Clojure lint tool Eastwood will warn about such name shadowing.

andy.fingerhut23:05:44

(in the specific case of using a name in function call position, and that name is a local binding that shadows one in the outer environment, IIRC)

andy.fingerhut23:05:04

More details on that Eastwood warning here, if you are curious: https://github.com/jonase/eastwood#local-shadows-var