Fork me on GitHub
#beginners
<
2018-05-13
>
runsfastman03:05:08

Hey there, I'm learning clojure right now and I'm trying to figure out why the following doesn't work as expected:

runsfastman03:05:25

=> (def addem #(apply + %&))
=> addem 1 2 3

runsfastman03:05:39

I would have thought it would add the numbers but it prints

dadair03:05:57

Are you wrapping the call in parens? (addem 1 2 3)

montanonic06:05:05

Heya clojurians, I'd like to take a structure like [1 3 2 1 1 3 1 1 1 2], and return a nested structure with all runs of equal data in their own vector, like [[1] [3] [2] [1 1] [3] [1 1 1] [2]. I'm struggling with the best way to do this. Ideas?

montanonic06:05:51

A lot of the inbuilt functions like split-by or take-while, which is what I'd think of using for this, won't work because I need to compare elements with previous elements. Which implies using reduce, but I was hoping their would be a cleaner way, especially since updating nested data is kind of confusing.

seancorfield06:05:42

@montanonic Sounds like (partition-by identity coll) to me?

👍 4
seancorfield06:05:32

That produces a sequence of sequences, so you'd need to (mapv vec ...) if you really want a vector of vectors...

montanonic06:05:34

Oh, woah, nice

montanonic06:05:53

yeah I'm not particular about the output in this case

seancorfield06:05:39

(this is just one of those cases where years of exposure to Clojure gradually teaches you more and more of the core functions 🙂 I'm still learning after eight years!)

montanonic06:05:30

🙂 totally

montanonic06:05:09

Glad I asked here for help, wouldn't have thought of this.

andy.fingerhut06:05:16

Reminds me that someone created some code where you could give example inputs and outputs that you want, and if there was a known existing function that could do it, it would tell you. Anyone remember where to find that?

andy.fingerhut06:05:57

Found what I remembered, but haven't tried it out yet to see if it would answer the question above: https://github.com/Raynes/findfn

malikdanishk08:05:08

Is anybody familiar with 'async/map'? Any resources would be really helpful

val_waeselynck10:05:18

Not sure what you're talking about, do you have a link with more context?

grierson12:05:46

Are there any libraries that implement common spec’s? e.g. email telephone postcode?

sundarj17:05:03

perhaps you are looking for this: https://github.com/ioRekz/spectator ?

WhoNeedszZz14:05:26

How do people feel about the use of :as vs :refer in a require expression these days?

joelsanchez14:05:27

in our team we tend to :as everything, as it makes it easy to know where things are from, visually

WhoNeedszZz14:05:47

But are there any performance differences?

WhoNeedszZz14:05:01

Does :as load the entire namespace or does it simply create an alias?

joelsanchez14:05:15

it's just an alias, the namespace is loaded by requiring it

WhoNeedszZz14:05:30

We're talking about the require expression

joelsanchez14:05:06

the fact that you add :as or :refer has no performance impact, the namespace has already been required

WhoNeedszZz14:05:09

Say (require clojure.string :as str). Is the entire clojure.string namespace loaded or only the functions you use

WhoNeedszZz14:05:30

:refer explicitly only loads the supplied vars

joelsanchez14:05:41

those are just aliases, the vars are available anyway

WhoNeedszZz14:05:52

Ok you aren't following me then

noisesmith14:05:08

there is no way to partially load an ns

noisesmith14:05:10

there's no such thing

WhoNeedszZz14:05:24

I beg to differ

noisesmith14:05:32

in clojure, there's no such thing

WhoNeedszZz14:05:45

:refer [foo bar] is much different than :refer :all

noisesmith14:05:03

it just changes aliases, it doesn't change what's loaded and accessible

noisesmith14:05:35

you don't need refer or as

WhoNeedszZz14:05:52

I'm calling bs on this

noisesmith14:05:55

it's just extremely bad style not to use them

noisesmith14:05:58

you are wrong

joelsanchez15:05:09

even if you were right this is not the best way to communicate

☝️ 12
WhoNeedszZz15:05:28

:refer [foo] and then try to use bar from that namespace

noisesmith15:05:10

you just need to use the full ns prefix

noisesmith15:05:13

this is only about names

noisesmith15:05:33

(don't do it that way, it's bad style, but there's no way to "partially load" an ns, it's all or nothing)

WhoNeedszZz15:05:51

That doesn't seem right at all based on the philosophy of Clojure

WhoNeedszZz15:05:02

That's like doing import * from foo in Java

noisesmith15:05:07

I can literally show you things working that way in a repl

noisesmith15:05:15

yes, it's a bad idea don't do it

noisesmith15:05:26

what I'm saying is partially loading an ns doesn't exist, it's not a clojure feature

WhoNeedszZz15:05:27

What you're saying would be the same thing

noisesmith15:05:20

+user=> (require 'clojure.set)
nil
+user=> (clojure.set/map-invert {:a 0})

noisesmith15:05:36

you can do this with any ns and function - just don't do it

noisesmith15:05:50

:as and :refer are tools to make your ns cleaner

WhoNeedszZz15:05:14

That's not what I'm talking about

noisesmith15:05:35

what do you mean by "partially load" then?

noisesmith15:05:24

:as creates aliases with a prefix, :refer creates aliases to specific symbols, neither changes what's loaded

WhoNeedszZz15:05:36

So if we are in agreement that import * from foo is bad practice, how is Clojure loading the entire namespace good practice? It's the same thing

noisesmith15:05:17

@whoneedszzz in java you can load classes separately, in clojure you can't load parts of a namespace separately

noisesmith15:05:42

like literally, in java, you only load the classes in a package that have been referenced

noisesmith15:05:51

if you don't mean loading, use a different word

noisesmith15:05:30

if you just mean creating aliases within a different scope, that's different - the whole thing is loaded, it's just that only certain aliases are made

noisesmith15:05:14

it might be a bad choice? I can't think of any language that loads up only parts of a file - in java each class is one file so that's the modularity of loading

dpsutton15:05:37

And it would be impossible to determine statically which parts of a namespace would or could be used

noisesmith15:05:54

right, your ns file would need to have some kind of database format maybe, with metadata about granular dependencies? not sure how it would work

WhoNeedszZz15:05:21

I guess I'm just not understanding how Clojure can load the entire namespace and not have the same problems Java has with import * from foo

noisesmith15:05:36

because it doesn't change scope

noisesmith15:05:48

even in java, you can use all of foo just by using the full name of each class

noisesmith15:05:25

because we avoid refer (or only use it for specific symbols) and we use :as to qualify the names, we avoid implicit scoping - but that's not a loading issue, that's a naming and scope issue

WhoNeedszZz15:05:30

Ok let's try a different approach

WhoNeedszZz15:05:36

Why is import * from foo bad?

noisesmith15:05:47

because I see symbols and I don't know where they came from

noisesmith15:05:55

:as avoids this issue by applying a prefix

noisesmith15:05:20

:refer mititages it slightly by only bringing in a small list of symbols and not everything

WhoNeedszZz15:05:35

"And not everything"

WhoNeedszZz15:05:40

How is that not partial loading?

noisesmith15:05:48

because that's not what load means

noisesmith15:05:04

loading is taking a resource outside the program and turning it into part of your program

dpsutton15:05:05

Difference between bringing in names and bringing in the functions

noisesmith15:05:31

that's partial import, import implicitly loads but isn't identical to loading

noisesmith15:05:41

these names mean very specific things

WhoNeedszZz15:05:48

Ok so if you corrected me on the word from the start we would be on the same page

noisesmith15:05:56

I did, multiple times

WhoNeedszZz15:05:56

The word I meant was "import"

WhoNeedszZz15:05:45

Does using :as in a require statement import everything in that namespace?

noisesmith15:05:22

it aliases everything with a prefix into the current ns

WhoNeedszZz15:05:49

That does not answer my question

noisesmith15:05:06

import is for classes, it has nothing to do with other namespaces, it creates an alias to a class in the current ns

noisesmith15:05:53

alias is for namespaces, it creates a prefixed alias for each public var in the target into the current ns, and yes, it does this for all of them

noisesmith15:05:39

in practice, refer is worse than as in terms of explicitly knowing where things come from, because as makes it clear via the prefix that something is external

👍 4
WhoNeedszZz15:05:53

So if you are only using 1-2 vars in a namespace that has 20 vars why would you want to use :as then

noisesmith15:05:55

but, sometimes refer is worth it because you use something enough that the prefix is too noisey

noisesmith15:05:02

in practice I do, yes

noisesmith15:05:25

that's normal in the clojure community

joelsanchez15:05:28

to know where it's coming from. :refer hides this info

WhoNeedszZz15:05:53

But as you said that't not all that is happening

WhoNeedszZz15:05:10

:refer is only referencing what is supplied to it

WhoNeedszZz15:05:15

Not the entire namespace

noisesmith15:05:25

but it ambiguates all its args

noisesmith15:05:41

when I'm down further in the ns, I need to remember the names of all referred items and where they came form

WhoNeedszZz15:05:45

If you use sensible naming conventions that shouldn't be a problem

noisesmith15:05:52

as makes the provenance explicit, it's never ambiguous

joelsanchez15:05:10

if you named everything with 60-char names, sure

WhoNeedszZz15:05:46

update vs updateStatusBar

joelsanchez15:05:02

how about status-bar/update

👍 12
WhoNeedszZz15:05:17

That's poor naming

WhoNeedszZz15:05:39

That makes it necessary to use the namespace

noisesmith15:05:48

then if you are right, clojure uses poor naming. It works out for me. Best of luck!

noisesmith15:05:04

no, status-bar isn't the full namespace, that's a shitty namespace name, it's the alias

👍 4
joelsanchez15:05:10

why would you prefix all vars inside a namespace with the name of that namespace?

WhoNeedszZz15:05:21

I wouldn't and didn't suggest that

dpsutton15:05:10

I use the alias to namespace things. I explicitly like the alias there

mg15:05:11

@whoneedszzz what do you mean by, "use the namespace"?

joelsanchez15:05:13

inside the com.whatever.app.status-bar namespace, of course everything is related to status-bar, so you can have an update fn there, and refer to it as status-bar/update, with :as

👍 8
dpsutton15:05:16

That way the function can be named simpler and the alias gives information

WhoNeedszZz15:05:36

(:require [foo.bar.status-bar :refer [update-status-bar]]) means I can now do (update-status-bar ...) and know exactly where it came from and what it does

joelsanchez15:05:54

so you suggest suffixing every fn in status-bar with status-bar

WhoNeedszZz15:05:24

You keep putting words in my mouth

mg15:05:29

Why would you want to repeat "status-bar" in the name? It's already there in the namespace?

👍 8
WhoNeedszZz15:05:09

Is it the only component of this hypothetical app that has an update function?

joelsanchez15:05:20

of course, that's why you use :as

WhoNeedszZz15:05:40

So what you guys are talking about means that you must use :as because they are both called update

mg15:05:16

Generally I don't do my naming with accommodating people who use :refer too much as a concern

👍 4
WhoNeedszZz15:05:36

What is "too much"?

noisesmith15:05:57

if a var isn't used in at least half the functions in my ns, I don't refer it

WhoNeedszZz15:05:08

From what has been said here it is purely a stylistic choice

noisesmith15:05:15

even then, I only refer if the refer makes the code significantly easier to read

mg15:05:31

Stylistically, it's probably best to only use :refer for things that are repeatedly used in a ns, and I also strongly disfavor :refer-ing in anything that's domain-related

WhoNeedszZz15:05:36

So I consider using the alias repeatedly in the code as noise

WhoNeedszZz15:05:51

When the namespace is given when you use :refer

noisesmith15:05:59

every mainstream library out there disagrees, if you read the source

WhoNeedszZz15:05:13

Good for them?

WhoNeedszZz15:05:25

Doesn't make it the best choice

noisesmith15:05:33

we don't have to argue about naming, I doubt anyone here is going to change their mind

noisesmith15:05:50

it's a beginners channel for learning clojure, we can tell you what's normal, idiomatic

noisesmith15:05:58

if you want to change the whole community, this isn't the venue

noisesmith15:05:06

if you want to justify your own naming practices, why?

WhoNeedszZz15:05:13

Again, putting words in my mouth

WhoNeedszZz15:05:32

Par for the course for text communication I suppose

noisesmith15:05:46

cheers, have fun learning clojure

WhoNeedszZz15:05:05

I'm not a beginner. I just thought it was a beginner question

WhoNeedszZz15:05:22

Strange that you would assume that

dpsutton15:05:55

It's an assumption for people in beginners. It's the point of the channel.

dpsutton15:05:24

And the inference is beginning clojure not necessarily beginning programming

WhoNeedszZz15:05:49

The point is to help beginners. I posed the question in case any beginners were wondering the same thing and if I asked it in #clojure they would likely never see it

WhoNeedszZz15:05:22

Hence why it is a poor assumption

mg15:05:28

@whoneedszzz It's also possible to rename symbols that you refer in, if you prefer to do things in your style but are dealing with symbols that don't have prefixes in their names. require supports a :rename flag

WhoNeedszZz15:05:17

How is that my style?

noisesmith15:05:22

just for clarity, this is how the discussion started

07:54:26    WhoNeedszZz | How do people feel about the use of `:as` vs `:refer` in a require expression these days?                 │
07:55:27    joelsanchez | in our team we tend to `:as` everything, as it makes it easy to know where things are from, visually      │
                        | (edited)                                                                                                  │
07:55:47    WhoNeedszZz | But are there any performance differences?                                                                │
07:56:01    WhoNeedszZz | Does `:as` load the entire namespace or does it simply create an alias?                                   │
07:56:15    joelsanchez | it's just an alias, the namespace is loaded by requiring it

noisesmith15:05:45

imho the discussion could have stopped there, everything was resolved

WhoNeedszZz15:05:15

It wasn't resolved then because my actual question wasn't understood

noisesmith15:05:41

it was understood and answered - there's no performance difference, it's a naming alias

noisesmith15:05:15

beyond that what is there to do but argue about subjective style questions?

mg15:05:57

The style you were suggesting with the update-status-bar vs status-bar/update convention

joelsanchez15:05:09

a more interesting thing is - holy crap, it's 8AM in there! 🙂

noisesmith15:05:56

haha, west coast US and I don't tend to sleep in

mg16:05:40

@whoneedszzz from the original question, not sure what you mean by "loaded"

WhoNeedszZz16:05:53

I was drawing a comparison to Java where using import wildcards imports everything in that package and causes multiple issues because of that. One of them is a performance issue because the compiler has to search through the entire package of any wildcards to find the occurrence of the reference

mg16:05:03

require will cause the namespace to be compiled and instantiated if it's not already, regardless of :as or :refer

WhoNeedszZz16:05:20

So that's what I was getting at

WhoNeedszZz16:05:31

And now understand that

WhoNeedszZz16:05:43

Clojure handles it differently

WhoNeedszZz16:05:54

Another benefit to using :refer is that you can look at the top of the file and know exactly which functions and/or macros are being used in that namespace at a glance

boris16:05:09

I’m using lein-figwheel and trying to write a pixi.js application in clojurescript. I can’t get hot-reload to work correctly. If I mount my application to the dom using replaceNode, I have to do a hard browser refresh in order to see changes

(dom/replace-node
  (oget js/document "body")
  (oget app "view"))
On the other hand, if I mount it using appendChild, then every time I save a change, another canvas is appended to the page without removing the previous. Why does figwheel work so well with reagent and how can I make it work better for pixi?

noisesmith16:05:05

are you doing the replace-node at the top level of the ns? figwheel has to load your full ns so anything in a top level form will run

noisesmith16:05:22

usually there's a specific callback for figwheel that you tell it to call after each reload

noisesmith16:05:47

the reason things work so nicely with reagent is that you set up a piece of data that will cause a re-render of the mounted node when chaned

noisesmith16:05:17

(which means figwheel needs no special callback - if the data changes when reloading the code, the page refreshes)

boris16:05:14

Ah, I am using it in the top-level. I think the figwheel template’s default name for that callback is on-js-reload. So, it sounds like I should put my reload logic in there

noisesmith16:05:45

right, and whether in cljs or clj, doing things that have side effects at the top level of a normal ns will cause problems

grierson16:05:04

What is the equalivent discriminated union or Sum type for Clojure?

noisesmith16:05:25

clojure doesn't have a "compile only" mode, if there are side effects in your ns outside something like fn or delay that defer them, they run when your ns loads

noisesmith16:05:39

@grierson that really depends on what you are trying to do - there's no direct analog as clojure doesn't enforce types during compilation

noisesmith16:05:35

but depending on what you are attempting, it could be a multimethod extended to multiple keywords, or a protocol extended to multiple records, or a multimethod extended to multiple values of a magic key in a hash-map

boris16:05:17

Thanks @noisesmith, this gives me enough guidance to solve the problem

👍 4
noisesmith16:05:04

@grierson another important difference is that clojure doesn't really do "closed types" - so the natural solution to most things involving datatypes is going to leave it open to runtime extension

grierson16:05:55

@noisesmith I’m watching “The Power of Composition - Scott Wlaschin” presentation now. https://youtu.be/vDe-4o8Uwl8?t=1456

noisesmith16:05:07

from a brief glimpse, we'd use a multimethod or protocol for that

noisesmith16:05:38

if you try to apply ml patterns to clojure (beyond the very basics) you'll learn a lot, but you'll end up with very weird clojure code - ml and clojure have some incompatible base assumptions

noisesmith16:05:56

what mls and lisps mean when they say "functional" is distinct

noisesmith16:05:28

(btw I'd love to be using OCaml at work, but Clojure is pretty cool too)

dpsutton16:05:52

Have ocaml got their threading model done yet? Last I heard it was essentially single threaded with one or two proposals of how to accomplish it but nothing official yet

andre.stylianos18:05:32

as far as I know there's already a proposal that's been accepted which is under active development (multicore under ocaml-labs). Looks like there's been a lot of thought put into it which is why it's taking a long long time.

andre.stylianos18:05:49

It is dependent on other things like the addition of typed effects as well from what I remember/understood

noisesmith16:05:03

yeah, that is a problem with ocaml - it has good ipc so for a pool you can viably use a fixed number of instances on one machine, but it doesn't have shared-resources threads

dpsutton16:05:18

I think @bronsa uses ocaml as his primary language at work

noisesmith16:05:34

but f# (which is what was specifically being referenced) can use c# threading and is based on ocaml - I don't have experience with it though