Fork me on GitHub
#beginners
<
2017-05-02
>
notkevinc00:05:01

I have some string parameters that I want to pass from my server (Django templates) to the clojurescript app. In Elm there is a way to pass parameters to initialize an app. I don’t see this pattern in any of the tutorials or docs for cljs (that I’ve found). Is there a standard way to bootstrap a cljs app with parameters after the document has loaded?

notkevinc01:05:02

Kind of a related note, but I used a lein template to create this project, and I’m unclear where it is determined that core/init! is called on load.

noisesmith02:05:37

that should be in the :cljsbuild config in the project.clj

notkevinc03:05:31

Ah, thanks @noisesmith. I tracked it down to env/cljs/. I wasn’t looking there before.

notkevinc03:05:32

But I still have the question about bootstrapping cljs with config passed in from the html page. I’m using re-frame if that matters.

notkevinc03:05:44

If anyone would be able to help.

matan06:05:05

@noisesmith @donaldball @tbaldridge @mobileink it really kept me going in my sleep, the relationships between the multimethod system, records and protocols. In my perspective, the core differences lie in what kind of abstraction one has in their head and different ways of making one's code extendible by others through a shared mental model. And I learned of some performance differences and mild syntactic ones. I also learned of the type hierarchies model, mostly related to the multimethod system. The historical aspect of why one mechanism was introduced before the other seemed to mainly emphasize how eschewing Java concepts was initially more important than devising the later mechanisms, thusly admitting one hammer misses a lot of nails. It also spoke to the anthropology of speaking to people through differences from prior art (Java) before making time to address well-roundedness.

matan06:05:27

thanks for the discussion, I probably can say I understand the language (better) now.

matan06:05:37

@noisesmith @donaldball @tbaldridge @mobileink you don't really have to read that, it is sometimes just helpful to recap on learnings, and I just don't have time left now, to make a blog post or something 🙂

stardiviner09:05:47

Which library has scan function? (scan + [1 2 3])?

dominicm09:05:54

stardiviner: what should it do?

stardiviner09:05:41

I don't know, seems used in parallel programming, I found it in this video: https://www.youtube.com/watch?v=eRq5UBx6cbA

curlyfry09:05:47

The talk is a bit high level, there is no built-in function called scan in Clojure. The concept of a scan is a reduce but with every intermediate result included in the final result. It is not used for parallel programming, in fact the point he made in the talk was that parallelizing scan results in more work being done than in the serial case. While the is no function named scan in Clojure, we have reductions which produces the same result (and has a clearer name): (reductions + [1 2 3]) ;=> (1 3 6)

stardiviner12:05:10

@U0J30HBRS Thanks for your explain.

sb12:05:08

If somebody have experience with clojure - electron app generation, please drop me a line, about how to setup successful an icon. Many thanks. I tried with --icon app creation but in this case I see just an empty icon.. any other idea?

matan17:05:29

So this was bound to happen sooner or later: I have (1) a function of mine which I use in some places, and I wish for (2) a macro of mine, to use it in some other places. In use I mean either bring it along with it, or literally embed inside of it. Or anything else idiomatic to reuse the function also "by" the macro, making the macro safe to call from whatever namespace? Now for some reason I'm against embedding it literally. As is, the function is not found at runtime where my macro is expanded, because it is coming from a different name space in my code (a util namespace of mine). So I use my util namespace wherever I call my macro. Which won't scale very elegantly for the general case the more I write and use macros... So two questions about this: • This has been a curiosity for me for a while ― is there some way of telling clojure to not only use or refer a namespace in the current namespace, but to also expose it to those that consume the latter namespace? sort of a transitive use if you must. • Best practice for this use case?

tbaldridge18:05:21

I don't recommend using use at all, and instead use (:require [foo.bar :as fb]) and then fb/qux. This way you don't pollute the local namespace with names from another namespace. Also it's easier to track down where a symbol came from because you can go lookup what fb means and that takes you to the namespace where qux was defined.

noisesmith18:05:15

@matan it sounds to me like your problem is caused by not using ` for your macro, and instead embedding raw, unnamespeced symbols, in your macro generator

matan18:05:53

@noisesmith think you are right, let me first see how I can rewrite it

noisesmith18:05:12

the unnamespaced symbol might be valid in the namespace which defines the macro, but it won’t be valid in the namespace in which the macro is expanded

noisesmith18:05:20

this kind of issue is why ` was invented

matan18:05:46

will be on it in a while

noisesmith18:05:07

your fix is usually to literally replace ‘foo with `foo

noisesmith18:05:20

(and later consider using ` to create the whole form)

matan18:05:29

and as an aside, can required symbols somehow propagate along with the namespace where they are required? so that namespace A refers a symbol foo from namespace B, and when A is required in some other namespace C, C can use the symbol foo?

noisesmith18:05:22

there’s re-export macros out there, but I consider it a sign of bad design

matan18:05:46

sometimes I think it might be helpful though, e.g. I have this ceremony in some of my namespaces:

matan18:05:30

now that's because the authors of the library split it all in two, fair enough, modularity, they chose not to encapsulate under one name

noisesmith18:05:36

well, you hopefully don’t have two require blocks in one ns form

matan18:05:47

yeah I should squash them

noisesmith18:05:51

specifying both explicitly is a feature

noisesmith18:05:20

I should be able to see from my ns form exactly which file to look at to see what is up for a function

noisesmith18:05:28

implicit requires, implicit refers, all break this

matan18:05:32

so point being, I am tempted to merge them in a proxy namespace, making my ns definitions more concise

matan18:05:11

so I gather from your last comment, that this would break traceability (unfortunately)

noisesmith18:05:12

and you turn something simple, direct and declarative into a treasure-hunt when someone has to find the code

noisesmith18:05:41

(which is why we don’t tend to do this, and why clojure doesn’t support it directly)

matan18:05:46

well that's more like a limitation of the language, then

noisesmith18:05:52

an intentional one

matan18:05:01

or the clojure folk are against "encapsulation"

matan18:05:11

sorry for using the e word 🙂

tbaldridge18:05:51

No, it's about simplicity. The more ns magic you try to do, the harder it is for the next programmer to track down where a given var comes from.

matan18:05:21

Language (maybe) could have been designed to make it seamless, but I accept the limitation

tbaldridge18:05:41

If we had namespace require propagation (as Python does), it then becomes as @noisesmith said a treasure hunt of "where is this thing actually defined?

tbaldridge18:05:49

I used that model in Python, it's a major pain

noisesmith18:05:52

@matan I don’t want to need to start a program in order to edit its code - the text itself should suffice for understanding

matan18:05:36

well that's a statement @noisesmith let me see how much it fulfills as I grow my clojure 😉

matan18:05:01

anyway sorry for stirring this up

noisesmith18:05:05

of course I need to run the code to know my own changes work - but we should strive for code to be a human-first document

matan18:05:25

noisesmith: kind of breaks apart the moment you do tinker defmethods and other dynamic stuff.... reading code is oftentimes the equivalent of compiling and running it in your head, unless you code to simple reading rather than good execution.

matan18:05:54

I'd say most people strike some balance in between, but that's not a scientific saying on my part 🙂

noisesmith19:05:40

the difference is that dependency injection (including defmethod and protocol usage) should be top-down if done well - that means that you know which implementation is pulled in based on either static config, or the concrete instance created at a high level of abstraction before calling into internals. and the internals by their nature should work regardless of which implementation flows through (and if they don’t that’s a testing and debugging problem of course)

noisesmith19:05:27

for example I use conj everywhere, I rarely need to think about which of clojure’s dozen or more concrete persistent collections I am conj-ing too, at most I need to remember if the thing is list-like or associative

matan19:05:57

maybe those are two very different examples, dep. injection and using a function like conj. I'll think about it again after running through some stack traces. Or you think of conj as a dependency in your code, then it is kind of the opposite, you don't care where it comes from as long as you guess the "contract"

matan19:05:18

mildly confused, ignore me

noisesmith19:05:16

conj uses an interface, the actual collection you conj to is effectively an injected dependency

noisesmith19:05:45

(and even could literally be one if you use a lib that extends the persistent collections)

matan19:05:00

I think you mean this at some higher level of code, like in namespaces or dependency injections. But at the micro, this "principle" might mean a lot of dumbing down of code.

matan19:05:25

No contradiction implied of course.

matan18:05:08

good to know it simply cannot be done

noisesmith18:05:30

oh, it’s not a stir-up, it’s just something I’m strongly opinionated about (and a big part of why I love clojure)

noisesmith18:05:43

@matan oh it can, I’m telling you why I don’t think you should

matan18:05:54

yeah those re-export macros

matan18:05:06

I'll avoid if it breaks traceability

noisesmith18:05:30

there’s at least one popular library out there where none of its namespaces have code for the functions you can call in those namespaces because all the code is generated by macros

matan18:05:30

thanks for not mentioning the name, in the spirit of "you shouldn't even find it" 😆

dpsutton19:05:11

@noisesmith i can think of a library that does exactly that as well

dpsutton19:05:30

unless that's what you're talking about

matan19:05:22

@dpsutton thanks for not mentioning names 🙂 eventually I'm gonna get a drive to mimic it just cause it is forbidden https://www.youtube.com/watch?v=RnqAXuLZlaE

dpsutton19:05:18

i'm not sure why we're tiptoeing around naming a library. the library explicitly says these are experimental ideas

matan19:05:37

I'm going to avoid experimental...

tbaldridge19:05:28

Yeah, go ahead and name it. Criticizing code is different than saying "X is a fool for writing this..."

tbaldridge19:05:50

IMO it's fine to discuss the shortcomings of software, just don't project those shortcomings onto the author.

matan19:05:01

In scala (where I came from) you don't discuss shortcomings Everyone pretends everything is fine: case classes are fine, lack of concurrency idioms outside akka is fine. the horrendous build tool DSL is fine. etc.

matan19:05:15

Obviously counter-productive

matan19:05:25

Only good for marketing

matan19:05:48

Ignore 🙂

noisesmith19:05:25

@tbaldridge since were OK with it, this is the lib in question - notice how empty these files are, it uses reflection to build functions for each method on a java api https://github.com/mcohen01/amazonica/tree/master/src/amazonica/aws

matan19:05:34

I'd say the use case justifies extreme measures!

rauh19:05:41

That's smart though and justified.

tbaldridge19:05:46

Yeah it's an interesting trade-off, and one I've had to make in some libraries. The other option, which personally I'm a fan of, is to expand those macros into thousands of lines of CLJ code. That way you get static analysis and auto-generated code.

rauh19:05:56

I thought you guys were talking about all the libs with potemkin/import-vars

elena.poot05:05:03

rauh: declaring the var before importing it makes cursive happy

dpsutton19:05:11

that's what i thought as well

rauh19:05:46

I'm just annoyed because I don't get any of these vars with Cursive 😕

tbaldridge19:05:24

1000 lines of auto-generated boiler-plate (honestly it should be generating more), so you get static analysis at the cost of having giant blocks of machine generated code

noisesmith19:05:58

at least that way if I don’t get a function (or why it’s behaving the way it is) it takes me a lot less time to figure out what exactly it is

tbaldridge19:05:09

agreed, and that's why I prefer code generation over macros at times. With macros you loose line numbers, "jump to symbol" etc. But macros are more "lispy". So i've done it both ways from time to time.

matan19:05:29

can't one do "code generation" by somehow saving the outputs of macro application? doesn't the compiler support that? one nice thing in Scala is the compiler plugin architecture

tbaldridge19:05:49

sure you could do that with macros. And we have a plugin system for our compiler....it's called "macros" 🙂

tbaldridge19:05:07

core.async doesn't touch the compiler.

matan19:05:52

@tbaldridge oh I meant can you tell the compiler to dump the result of the macro evaluation phase to disk, or expose it as data, rather than write macros that take care of that? anyway I hope it can be gracefully accomplished, ignore ... 🙂