Fork me on GitHub
#clojurescript
<
2016-12-20
>
Pishty01:12:42

hello guys, how do i add two presistant vectors together, such as [1 2 3] + [4 5 6] = [1 2 3 4 5 6]

Pishty01:12:38

into - i asked too fast my bad

Pishty01:12:34

thank u @chrisoakman, is the only difference between concat and into is the return type - list and vector respectively ?

chrisoakman01:12:27

concat always returns a lazy sequence (a list), into can convert between difference sequences types. ie: (into #{} [1 2 3]) returns #{1 2 3} (converting a vector into a set)

Pishty01:12:18

oh i see so with into u can specify the return type ?

chrisoakman01:12:42

And depending on what you're converting between, into will function differently.

Pishty01:12:08

ah ok so it can append to the front or tail depending on the return type ?

chrisoakman01:12:17

For example, (into #{} [1 1 2]) returns #{1 2}

chrisoakman01:12:36

conj is typically used to add one item to a sequence, it adds to the end of a vector and to the beginning of a list

chrisoakman01:12:34

In general, most of the core library sequence functions return a lazy sequence.

chrisoakman01:12:04

So you'll have your vector / map / set data structure, you execute a couple of functions against it (during this time you are dealing with lazy sequences), then you often convert it back to whatever format makes sense.

chrisoakman01:12:46

I'm generalizing here: it doesn't always have to work in that way. But often it does.

Pishty01:12:12

i think i understand, so if i do an 'into' the return type isnt always a lazy sequence ?

chrisoakman01:12:17

You may find the ClojureScript cheatsheet helpful: http://cljs.info/cheatsheet/

chrisoakman01:12:51

That is accurate. With into you can specify which return type you want.

Pishty02:12:14

ah ok cool @chrisoakman you are the man, thank u so much, also i think am going to bookmark that cheatsheet 🙂

Pishty02:12:03

i need to get my head around the lazy sequence nature of clojure

chrisoakman02:12:35

It was something that took me a while to grasp when I first started. I was used to everything being "instant" in that you didn't have the lazy sequence abstraction.

chrisoakman02:12:29

I used a lot of doall to make sure things weren't in a lazy sequence all over my code. It was unnecessary.

Pishty02:12:21

you mean the doall wasnt necessary ?

chrisoakman02:12:19

Also the core library is large and there is a lot of overlapping functionality. In time you get familiar with it and this stuff becomes second nature though 🙂

chrisoakman02:12:10

doall forces a lazy sequence to evaluate, which is sometimes what you want if you need to see a results of a side-effecting function. doseq also does this

Pishty02:12:54

also mapv i believe

chrisoakman02:12:01

When I was first starting CLJS I used to write a lot of side-effecting functions in my code. I don't do that as much anymore.

Pishty02:12:11

when u say side effecting function .... would u be so kind as to provide an example of what u just stated or a link that explains it

chrisoakman02:12:10

There are multiple ways to explain this and I have someone en route to my house, so let me see what I can do in the next 5 minutes 🙂

chrisoakman02:12:59

When you think of a pure function, you think like math functions. Inputs always yield the same outputs: https://en.wikipedia.org/wiki/Pure_function

chrisoakman02:12:04

So in your program, some functions are that way (like "add 2 and 3 together"). But others will be different depending on what time they occur. For example: save this file to disk.

chrisoakman02:12:42

Essentially, anything that has to change state or communicate with the outside world. Often in the case of CLJS it's interacting with the user or the DOM (which is a stateful thing).

chrisoakman02:12:27

So most of the core library functions are pure. They don't change any state and they always work the same way regardless of their inputs.

chrisoakman02:12:07

In Clojure it's best to isolate your non-pure functions from your pure ones. Keep things clean and separate.

Pishty02:12:38

ah ok, so keep everything lazy until u hit the side effecting function ?

chrisoakman02:12:49

When I was new to Clojure I used to combine everywhere, which is often what you do in JS (and other languages). ie: loop over this array, and update some data, but also update the DOM

chrisoakman02:12:53

Yes. Well said.

chrisoakman02:12:47

So I used to use map to iterate and then doall to make sure the side effects happen.

chrisoakman02:12:45

Generally speaking, use core functions to change from Data Format A to Data Format B to Data Format C (whatever you need to do), then have some other function or process that handles the end result. Don't complect the data munging and the side-effecting.

chrisoakman02:12:17

Clojure makes this easy to do, especially with core library functions.

Pishty02:12:09

so when u seperate pure and non pure, do you put them in different namespaces or do u just name them differently ?

chrisoakman02:12:59

Really depends on your program, but probably it's just a naming choice.

chrisoakman02:12:58

It's convention to append a bang at the end of a function name that is side-effecting. ie: delete-table-rows!, show-login-button!, etc

chrisoakman02:12:27

Without even seeing the function definition, I already have a pretty clear idea of what those functions do 🙂

Pishty02:12:11

i've seen those naming conventions before i was wondering what the bang was all about

chrisoakman02:12:24

And the ! communicates to me that that function is not pure. (again, this just a convention, it's not enforced by the compiler or anything)

Pishty02:12:08

makes sense man, thanks again !

chrisoakman02:12:47

Sure thing 🙂

sova-soars-the-sora02:12:51

A bit off-topic, but does anybody happen to know, geographically-speaking, where one would have the greatest likelihood for running into a clojurian/clojurescriptian? Seattle?

chrisoakman02:12:07

At a Clojure conference 😉

tankthinks02:12:39

@pishty, I’m late to this discussion, but this blog post helped me understand when to use pure vs impure

tankthinks02:12:46

Also, https://github.com/Day8/re-frame events and effects are a nice place to start if you’re doing UI stuff in Clojurescript

Pablo Fernandez07:12:48

My index.html does this:

Pablo Fernandez07:12:59

goog.require("screensaverninja.core"); screensaverninja.core.main();

Pablo Fernandez07:12:49

which used to work just fine but now I’m getting: Uncaught ReferenceError: screensaverninja is not defined

Pablo Fernandez07:12:52

on that second line.

Pablo Fernandez07:12:01

If I run it in the console, it works.

Pablo Fernandez07:12:21

It used to work, but I don’t know what changed. I tried going back to a good commit and they all seem to be having the same problem.

robert-stuttaford08:12:13

does your cljs build define a :main, @pupeno ? because that saves you from having to do this ceremony. you simply load your js onto the page

Pablo Fernandez08:12:30

No, I don't think so. I do that for prod compilation, not dev.

Pablo Fernandez08:12:56

Separating the require and actual call to main in two script tags solved the problem.

Pablo Fernandez08:12:43

After reading how require works, I don't understand how this ever worked.

Pablo Fernandez08:12:22

I'm on the go now. When I'm back I'll check about just using :main.

thheller09:12:46

@pupeno the require and the main call need to be in separate <script> tags in case you are not doing that

Pablo Fernandez09:12:29

But I wasn't. How did it ever work?

thheller09:12:37

ah hehe skipped over that line reading chatlog 🙂

danielgrosse10:12:01

When compiling javascript with the closure compiler, i use the option source_map_location_mapping to redirect the source map location to an internal server. Unfortunately this isn't available for the cljs compiler. How could I achieve this behavour?

thheller10:12:25

@danielgrosse I think there is :source-map-path but not exactly sure, should be in wiki

dpiatek12:12:56

hi all, clojurescript noob question. I have the below function:

(defn config [recognition-instance grammar-list-instance level-grammar]
  (.addFromString grammar-list-instance level-grammar 1)
  (set! (.-grammars recognition-instance) grammar-list-instance)
  (set! (.-lang recognition-instance) "en-US")
  (set! (.-interimResults recognition-instance) false)
  (set! (.-maxAlternatives recognition-instance) 1))
When compiled with :advanced the .addFromString call turns into $instance$.$addFromString …. $addFromString$ does not exist on the object so it explodes with function is undefined. Can I avoid google closure changing the name of that? The object is an SpeechRecognition instance https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition .

dnolen12:12:47

you need to provide an externs file for those things if you want to use advanced compilation

dpiatek12:12:54

great, will look into that, thanks!

dpiatek14:12:44

thanks @darwin , that’s good to know as well

Alex Miller (Clojure team)15:12:47

Quick reminder that the Clojure community survey closes Friday - would love to have your input! https://www.surveymonkey.com/r/clojure2016

bcbradley16:12:59

how would you integrate proto-repl's nrepl functionality with boot-cljs-repl as in this tutorial? https://github.com/magomimmo/modern-cljs/blob/master/doc/second-edition/tutorial-02.md

Pablo Fernandez18:12:10

When trying to load my app, I get the error: file:///…/screensaverninja/app_dev/app_dev/js/app/goog/base.js Failed to load resource: net::ERR_FILE_NOT_FOUND. As you can see, app_dev is there twice. Any ideas why? It should be there only once.

tankthinks18:12:11

@bcbradley you can connect to the nREPL port boot outputs as a remote repl with protorepl

Pablo Fernandez19:12:17

What’s the proper way to call the main function of my clojurescript app when I specify :main something.something?

jr19:12:02

what tool are you using?

Pablo Fernandez19:12:55

@jr is that for me? cljsbuild and lein.

jr19:12:55

IIRC lein-cljsbuild will only invoke the compiler and output build files

jr19:12:09

:main is only for a jvm clojure entry point

jr19:12:24

you have to add ^:export metadata to the "main" function of your cljs app

jr19:12:52

then you can call app.main() in a script tag (if you are in a browser)

jr19:12:07

(ns example.app)

(defn ^:export main [])

Pablo Fernandez19:12:01

ClojureScript also has a :main, but it only loads that namespac, it doesn’t call any function on it. I could just call the function from the HTML, but I want to know if I’m missing something.

jr19:12:00

yeah the main namespace specifies all the required dependencies for compilation

jr19:12:13

it's normal to call the exported function in whatever runtime you're using

jr19:12:57

boot-cljs has an option where you can specify a "main function". it adds an additional goog provide that calls the main function after the rest of the deps have been required

jr19:12:51

they're called "init-fns"

juhoteperi19:12:09

@pupeno You can just call the main function on the end of the namespace

juhoteperi19:12:59

In boot-cljs, the additional options exist only because Cljs :main didn't exist back when they were added.

juhoteperi19:12:49

Currently Boot-cljs will always overwrite :main using the generated shim namespace, but in future it will probably be possible to use own :main namespace

Pablo Fernandez20:12:05

juhoteperi Is calling main at the end of the namespace considered idiomatic? It sounds like every time the namespace is (automatically) reload, main would be re-run, which is not desirable.

juhoteperi20:12:51

Why it is not desirable? In my experience is needed to re-render the app (with Reagent).

juhoteperi20:12:59

To answer myself: Yeah, it does mean that if you run some expensive initialization (start loading some codesets from backend or something) code you don't want to run after every reload, you'll need to implement logic that checks if those are alreaded loaded.

juhoteperi20:12:04

But that seems fine to me.

Pablo Fernandez20:12:12

juhoteperi: because that would re-initialize the state, clearing it.

timgilbert21:12:08

Hi guys, I have an externs / JS interop question. I'm trying to use this externs file:

var aphrodite = {
  "StyleSheet": {
    "create": function () {},
    "rehydrate": function () {},
    "extend": function () {}
  },
  "StyleSheetServer": {
    "renderStatic": function () {}
  },
  "StyleSheetTestUtils": {
    "suppressStyleInjection": function () {},
    "clearBufferAndResumeStyleInjection": function () {}
  },
  "css": function () {}
};
...but I'm not sure how to invoke what would be the equivalent of this in JS-land:
var aphrodite = require('aphrodite');
aphrodite.StyleSheet.extend([foo, bar]);

timgilbert21:12:37

I thought it would be something like this:

(.extend (.-Stylesheet js/aphrodite) [foo, bar])
...but that's giving me a compilation failure "aphrodite not found"

timgilbert21:12:36

Can anyone see something wrong with the syntax above?

chrisoakman21:12:27

@timgilbert The most foolproof way to make sure JS code "survives" GClosure Advanced Compilation is to use strings.

chrisoakman21:12:59

I don't see that package listed in CLJSJS: http://cljsjs.github.io/

chrisoakman21:12:25

I also suspect that most CLJS users would prefer to use something like Garden for having CSS "in their code": https://github.com/noprompt/garden

chrisoakman21:12:35

Although I know that's not the question you asked; just providing some context here 🙂

chrisoakman21:12:52

If the JS engine is saying js/aphrodite "aphrodite not found", then require must not be putting that on the window object.

timgilbert21:12:35

I'm preparing a PR for CLJSJS, actually, just trying to test my work. FWIW, aphrodite does a different thing than garden (it's more about dynamic CSS construction to reduce CSS collisions, as I understand it)

timgilbert21:12:47

Thanks for the tip, though, I'll look for that

chrisoakman21:12:03

In general, I try to wrap JS interop in a function with a nice interface. So I might try something like this: https://gist.github.com/oakmac/fba1fa8cfb0ec07b55a4a1284761c2e6

timgilbert21:12:23

The library itself is actually written in Es6 and goes through webpack to export

chrisoakman21:12:33

I'm not 100% sure that will work, but hopefully you can see where I'm going with that.

timgilbert21:12:03

Thanks, I'll take a look. I seem to recall that aget is discouraged, though?

chrisoakman21:12:26

Yes; it's not officially encouraged to use aget to access object properties.

chrisoakman21:12:53

aget is for arrays. I still use aget because I know that dot notation in JS isn't going to change.

chrisoakman21:12:50

There is a nifty library that creates an oget function; I can't remember the name of it right now. It produces something like this though: https://gist.github.com/ptaoussanis/2556c56d93bde4af0415

chrisoakman21:12:16

Whatever 😉 aget works fine for me

jr21:12:12

goog.object/get is preferred for property access over aget

ag21:12:07

how can I use SNAPSHOT dependency of cljs? I want to use what’s in “master"

bbloom21:12:37

is there some trick to make enable-console-print! work correctly with figwheel? i’m seeing print output in the figwheel logs

mfikes21:12:02

@ag You build it and then put the version number in your project.clj if using lein.

bbloom22:12:56

uuugh ignore my question - somehow my damn console was changed to only show error messages

bbloom22:12:05

misclick 😕 what are mice even for

pandeiro22:12:11

Why in the Quick Start does it suggest the command java -cp cljs.jar:src clojure.main build.clj when build.clj already references the source directory to build?

pandeiro22:12:33

i.e. java -cp cljs.jar clojure.main build.clj works just as well

richiardiandrea22:12:38

@pandeiro your second version is more correct to me as well, the compiler does not build from the classpath I believe

thomassjogren22:12:48

Hello. Pretty new to cljs. What is a good lein template for regent and figwheel?

dnolen23:12:14

@pandeiro you need to set the classpath

dnolen23:12:47

forgetting to do that will only lead to more confusion later

pandeiro23:12:44

I understand the need to do that for cljs.jar but why src?

dnolen23:12:16

@pandeiro because src needs to be on the classpath

pandeiro23:12:48

ah ok i thought it compiled fine when i removed it in that example (but i didn't run the code)

pandeiro23:12:19

my understanding was that cljs.build.api/build could be passed any arbitrary dir as its first arg