Fork me on GitHub
#clojure
<
2019-06-15
>
introom02:06:15

for the macro, what is “fn*” ?

introom02:06:20

where is it defined?

sogaiu02:06:10

isn't it one of those things that's in Compiler.java?

dpsutton02:06:29

its known as a "special form".

dpsutton02:06:34

the docs are so so good. I need to spend a weekend just reading them. I always try to go to some authoritative source when i'm wondering or answering a question.

introom03:06:05

@dpsutton the doc doesn’t mention fn*

introom03:06:16

it only mentions fn

dpsutton03:06:30

That’s true. I think the only real difference is that fn allows for restructuring. Fn* is the actual primitive though. Check the sources I linked and you can see

seancorfield03:06:31

Several of the forms described as "special forms" are actually implemented as macros in terms of a * version of the form.

seancorfield03:06:47

fn is a macro in terms of fn*, let is a macro in terms of let*.

introom03:06:38

but how come fn* be accessed inside the definition of lazy-seq ?

introom03:06:49

if i type `fn*' in repl, it says such a symbol doesn’t exist.

introom03:06:52

my question is, fn* cannot be accessed in repl., but can be access in a clojure file, i.e., clojure.core

seancorfield03:06:29

fn* and let* etc are part of the compiler. They're not actual symbols.

seancorfield03:06:03

That's why, technically, fn, let, etc are considered the "special forms". Just assume they are magic in the compiler, rather than macros 🙂

Alex03:06:14

If I'm relatively new to Clojure (have done a few months of Clojurescript), is Duct a good library to use for building a web server / api? I like the config/data-driven approach, but seems like a lot of modular pieces to keep track of

Alex03:06:25

If not Duct, any recommendations?

seancorfield03:06:09

Sure, start with Duct and see how you get on. There are lots of good ways to build a web app with Clojure.

Alex03:06:50

Thanks Sean. I take it you've had pretty good experience with Duct?

seancorfield03:06:04

No, never used it.

seancorfield03:06:09

But it's solid.

Alex03:06:19

What have you used if you don't mind me asking?

seancorfield03:06:39

Mostly at work we use Ring, Compojure, Component, Selmer... and dozens of other libraries. One of our apps uses Bidi instea of Compojure. Most of our apps use the built-in Jetty adapter but one uses Netty.

Alex03:06:20

Cool, thanks Sean. I'll take a look at those others as well

seancorfield03:06:27

Clojure's way is to compose a whole bunch of libraries into an app -- so pick whatever speaks to you and see how you get on.

didibus04:06:14

I've been wondering if it would help to call some of those as micro-frameworks

didibus04:06:37

I feel some people have a harder time understanding how libraries would be stitched together. But really, a lot of these are small targeted frameworks And I've had some encounters where somehow by calling them micro-frameworks, it clicked more in people's head.

didibus04:06:41

Like library makes it sound like you'll have to do a lot on your own. When really, it's just that the glue logic is expressed in Clojure instead of say XML

Ahmed Hassan04:06:22

Libraries in Clojure/ClojureScript are more like DSLs. Or micro-frameworks as you mentioned.

seancorfield04:06:40

I disagree. Frameworks call your code. With libraries, you call their code. Clojure has libraries almost universally.

didibus05:06:07

That's how I define it as well. But I think there's a new kind of distinction that seems to help understanding what some of those libraries do. Like application frameworks of yore, such as Rails, Spring, etc. They clearly are the main entry point, and call into all your code, and are in control of it all. But something like Compojure, is more of a hybrid. You call it, but it also calls you. It'll call your routes handlers for you. It's still in control of a subset of the order of execution and context of execution of some of your logic in that sense.

didibus05:06:30

If all compojure did, was parse a route string against a URL, it would be different. But by adding that extra orchestration, it acts as a micro-framework of some sort.

didibus05:06:17

And then I looked around, and it seems in other languages, libraries like Compojure have also started to show up, and they're calling themselves micro-frameworks

didibus05:06:56

And I mean, the names don't matter much, but trying to explain some of this to others, I've noticed somehow, if I describe them as micro-frameworks, it seems to help them have a better mental model, and they follow along more easily.

seancorfield05:06:18

Compojure is just a higher-order function. Nothing more, nothing less.

seancorfield05:06:05

"micro-frameworks" is just buzzword b.s. 🙂

didibus05:06:48

Haha, ya I know. And they stem from languages where to just inject some code into a function, you need a gazillion of setup and a whole support DI framework 😛

didibus05:06:38

But for some reason, when I switched from answering: "What framework should I use for web development?" - You don't need a framework. In Clojure you just put libraries together yourself such as Compojure and Ring... TO: Oh yes, Clojure favors micro-frameworks, Compojure and Ring are the two most popular of them, try them out.

didibus05:06:02

It seems like the reception was way better. Like people are like... Oh awesome! I'll go try them out right away!

didibus05:06:17

So I guess the buzzwords sell and are motivating 😛

seancorfield05:06:27

I still think people should learn the right terms (libraries) instead of b.s. 🙂

didibus05:06:50

:man-shrugging: maybe I'm trying too hard

seancorfield05:06:38

I think most of the people you're trying to teach aren't trying hard enough.

seancorfield05:06:57

Clojure is hard to learn if you're coming from a "bad" place.

seancorfield05:06:18

There's a lot to unlearn before Clojure's simplicity makes sense.

seancorfield05:06:09

The obsession with "frameworks" must be unlearned. The "normality" of state and mutation must be unlearned. Assignment, mutable loops. All must be unlearned.

👍 8
seancorfield05:06:32

You can't just map this stuff down to other languages' terms and practices. Clojure really is different.

Ahmed Hassan07:06:32

Where do re-frame stand between libraries and frameworks?

jaihindhreddy10:06:16

I never quite got the "frameworks call your code and you call libraries' code". Take integrant (or equiv.) for example, is it a library because I call it to initialize/halt systems, or a framework because it calls my multimethods to initialize/halt my components? Any way you slice it, at the end of the day, it seems like there is some subjectiveness involved in calling something a framework/library. No matter what you call them though, these things are way more simple in Clojure than other ecosystems I've seen. Any thoughts on this highly appreciated.

💯 8
didibus04:06:00

First, a library is just a packaged piece of code that you can link against. So it's not really framework vs library, but just, some libraries are packaging framework like code, and others are not, thus some people say: this is *just a library; in the sense, I didn't include framework like code in here. This often is due to the assumption that a framework comes with a lot of machinery, and new mechanisms of interaction which you have to learn, understand and start using to leverage any reuse from the library. Where-as just* a library, means that it uses the existing known mechanisms of whatever language you use for code reuse, like simple function calls for example.

didibus04:06:13

Now, certain language lack simple mechanisms in order to re-use orchestration code. Like, you can call a method on an object, and it returns a result or performs an action. But what if you want to reuse a sequencing logic and override some of its steps? Some language make that difficult to do, so you need a lot of machinery to make it work. That's kind of where the crux of frameworks came from.

didibus04:06:43

And they started as Application Wide framework. The idea was, what if you want to reuse an entire financial application? And just customize pieces of it to a new use case?

didibus04:06:03

Take Django for example, a Web Application Framework. It's pretty much a full web stack, and then it started giving you more and more hooks into swaping pieces of it so you can re-customize it to implement different websites with it.

didibus04:06:38

Things like that are rigid, and all encompassing, they're "all in" offerings.

didibus04:06:59

That's generally what people mean when they talk about frameworks.

didibus04:06:38

Big monoliths, all encompassing, application level orchestrators, which have custom configuration mechanisms and extensibility mechanisms.

didibus04:06:40

Now, there are much smaller scoped frameworks. Very lightweight machineries, which take over only a very small portion of your application. So you still have to integrate them in your app, and call them yourself, like you would with things that are *just* libraries.

didibus04:06:03

Integrant is one such library.

didibus04:06:41

You can call it a micro-framework. That's what other languages are starting to call them. But I think Sean's point here was that, at that point, calling it a micro-framework is maybe a stretch. Especially in Clojure. That's because, the machineries used are all normal Clojure machineries. Either simple function composition, higher order functions, macros, or data-driven interpreters.

didibus04:06:19

So in Clojure, all that is *just* a library, because its just plain old Clojure.

didibus04:06:44

At least, that was my take. Sean can chime in in case I've misunderstood his stance.

seancorfield05:06:48

One of the few commonly-used libraries in Clojure that might be loosely categorized as "framework lite" is Ring, because it plugs in "above" your application code and it calls your functions. But that's a bit of a stretch given that you are specifically giving it a function to call.

seancorfield05:06:33

Frameworks tend to follow conventions or have specific configurations around "registering" your code to be called by the framework.

seancorfield05:06:04

Even with Ring, you are calling Ring functions to kick the whole thing off and passing your function to be called.

didibus05:06:07

Ya, to me, it boils down to two things: 1. Is it at the application level? Does it take over your whole application? Or like Sean said, is it above your application? 2. Does it use non-standard and custom configuration and extension mechanisms? As opposed to using common language features.

8
jaihindhreddy09:06:25

Makes sense. My intuition almost exactly lines up with this. I don't call my app an "integrant app" because I'm using that, but I do call it "Django app" when I'm using that.

didibus04:06:33

Hum.. that's a good question.

didibus04:06:14

I'm not sure actually. I think they are interned in RT.java

didibus04:06:46

So they aren't part of clojure.core

didibus04:06:34

The special forms are always available. They're the only thing you can use from a namespace that did not require clojure.core for example

didibus04:06:53

You could also maybe replace it for a call to RT?

didibus04:06:05

It's the Clojure runtime

didibus04:06:38

I'm on my phone. But I think something like (. clojure.lang.rt <not sure here>)

didibus04:06:58

Ya, what you're doing sounds hard :p

didibus04:06:33

Ya, probably a good way to learn about some the underlying foundation

dpsutton05:06:20

There’s a book called lisp in small pieces that you would enjoy. It details exactly this. And you make several scheme interpreters and compilers along the way

dpsutton05:06:20

But in general you look up the first form in an environment if it’s not a special form

dpsutton05:06:18

You probably already do this with your if implementation. It gets hard to see when your implementation language and implemented language are similar

dpsutton05:06:26

It does. I think it’s because they execute sequentially and can modify the environment

dpsutton05:06:38

If there’s no mutation perhaps it’s not a special form

dpsutton05:06:25

Let me think on that. Trying to remember without looking it up :)

hiredman05:06:33

You can make do a macro that expands to let

hiredman05:06:48

A lot depends on the semantics of the language, you are interpreting

dpsutton05:06:15

Does your implementation allow using defs and defmacro forms?

hiredman05:06:23

So for example, mydo breaks recur for clojure like loop/recur

hiredman05:06:52

Which a macro expanding to a let doesn't

didibus05:06:42

And this one is free online as well: http://www.buildyourownlisp.com/

didibus05:06:53

Did not read or try either, just had them bookmarked

hiredman05:06:06

But classically, let can be a macro expanding to anonymous function application, but that also doesn't work for clojure because it breaks the only constant space recursion mechanism

hiredman05:06:12

A let that ignores the bound symbol is a do

hiredman05:06:58

(do ... ...) =>`(let [_ ...] ...)`

seancorfield05:06:08

(let [_ nil]
  ...)
is like
(do
  ...)
(assuming ... doesn't contain _

seancorfield05:06:14

Yeah, what he said.

hiredman05:06:13

If you are writing your own language, you can just make tail recursion work properly, so who cares about recur

dpsutton05:06:59

If you look at the old chat logs it’s conversations like these with Brandon bloom and ztellman and probably hiredman about clojure like this.

introom07:06:28

what is (= foobar) for ?

introom07:06:34

e.g., (= 3) returns true

andy.fingerhut08:06:43

It is a degenerate behavior of the = function. It isn't terribly useful in many cases, but it does mean that you can, for example, take a collection foo and do (apply = foo) and you will get back true if all of the elements of foo are equal to each other.

andy.fingerhut08:06:37

Similarly reasoning for why many functions that normally take 2 (or more) args can in some cases also take 1, e.g. (apply + coll) also works to add up collections of only 1 number.

br09:06:52

Hi all, anyone out there using NATS Streaming with Clojure? Are you just using the official Java library?

kulminaator09:06:07

had no idea what nats even was, had to look it up .... br what's a good usecase for it ?

br09:06:08

Alternative to using Kafka (which is very resource hungry) for CQRS

kulminaator09:06:26

ok ... read up a bit ... smarter now ...

kulminaator09:06:39

we have been using rabbitmq instead of kafka for the very same reason

br09:06:11

Yes but we can't use pub/sub for this, we need persistent event log and topics (ala kafka)

br09:06:14

(kafkfa streams, I mean)

kulminaator09:06:31

we use the message queue just for reliable communications between microservices ... and there's so much chattery that long term storage would be out of the question anyway 😄

br09:06:55

We may use it for this also, but the more importing thing for us is the persistent event log

kulminaator09:06:43

for the stuff we want to persist we have a consumer that dumps stuff directly into s3

kulminaator09:06:05

i could never afford to keep it on amazon's gp2 or even magnetic drives 😄

introom15:06:06

does the `data driven’ in clojure mean we should use {} instead of defrecord?

andy.fingerhut17:06:09

I do not understand why being data driven would lead to a preference of one over the other. Both maps and records are similar, but not identical, ways to represent data.

andy.fingerhut17:06:47

At least until recently, maps could not participate in protocols, but records can. There are a few other differences between them that sometimes lead to a decision to use one over the other, but I do not think any of them involve "one is data, the other is not"

macrobartfast17:06:54

somewhat fuzzy on the authentication/authorization world... is it possible (or does anyone have experience with) using firebase for authentication and then the result of that for authorization on a non-google server?

macrobartfast17:06:53

I have the authentication with firebase part understood in a react app... just not sure how that all works with routes on one's server.

daniel.spaniel17:06:53

I am trying to get logging to work when i run tests with this style

daniel.spaniel17:06:56

clj -A:dev:clj-tests --watch

daniel.spaniel17:06:38

if i have println or timbre/log they don't show up .. trying to find out what will show up ? ! > ?

macrobartfast17:06:16

I guess a more specific question is: how does your server know when a firebase authenticated user is invalidated?

grav17:06:36

I’m looking for a nice way of sorting stuff based on some predetermined order. ClojureDocs comes up with https://clojuredocs.org/clojure.core/sort-by#example-542692cbc026201cdc326c2f, which seems nice, but doesn’t it recreate the lookup table for each comparison?

grav17:06:15

If so, how would you fix it? Pre-define the lookup table, or memoize? Pre-defining isn’t as self-contained (you need a def), so I’m thinking of memoize. Wrapping everything in a sort of (defn sort-by-order [order, key-fn coll]) interface also doesn’t seem nice, since it does not compose with eg juxt

dpsutton17:06:22

the callback from firebase will send you a user object. You can get jwt tokens from that. you can check them with buddy that the tokens are 1) not expired, 2) signed by google. These will have user details which can then be trusted

macrobartfast18:06:12

ah ok... so buddy sits on my server and communicates with firebase's servers somehow?

macrobartfast18:06:35

I'm understanding my client sends a callback object and then a jwt token (all this in the client) and the jwt token is send with requests to my ring app, which then checks with firebase directly.

macrobartfast18:06:15

you've confirmed that buddy will be what I want to look at.

macrobartfast18:06:27

or maybe the jwt is created on the server... at any rate I shouldn't be thinking aloud like this.

dpsutton18:06:10

if the frontend sends you a jwt you don't need to talk to firebase you just need to look at the token. Firebase has a java sdk as well though so you can use that if you like as well

dpsutton18:06:38

i did this with buddy at a previous job.

dpsutton18:06:08

google puts out a rotating list of signing keys somewhere and you check that the jwt was signed with those keys and then you can trust the jwt payload

macrobartfast18:06:15

ah ok... shapes emerging in the fog... basically, I have a ring based server of my own, but love firebase.

macrobartfast18:06:12

I should clarify, love firebase authentication.

dpsutton18:06:29

my strategy uses both.

dpsutton18:06:44

i'm not advocating one over the other but use both. Frontend sends credentials to firebase, gets authenticated. this gives a firebase user object in js. you ask that for a token which you can include in chatter to your backend. You backend can inspect the jwt, ensure its signed by google, and if it is, can trust the user info contained in there. Email, time logged in, when it was issued, etc

macrobartfast18:06:46

this is all fantastic news... I was getting worried I'd get locked into their firebase friendly services... sweet!

jaihindhreddy10:06:16

I never quite got the "frameworks call your code and you call libraries' code". Take integrant (or equiv.) for example, is it a library because I call it to initialize/halt systems, or a framework because it calls my multimethods to initialize/halt my components? Any way you slice it, at the end of the day, it seems like there is some subjectiveness involved in calling something a framework/library. No matter what you call them though, these things are way more simple in Clojure than other ecosystems I've seen. Any thoughts on this highly appreciated.

💯 8
didibus04:06:00

First, a library is just a packaged piece of code that you can link against. So it's not really framework vs library, but just, some libraries are packaging framework like code, and others are not, thus some people say: this is *just a library; in the sense, I didn't include framework like code in here. This often is due to the assumption that a framework comes with a lot of machinery, and new mechanisms of interaction which you have to learn, understand and start using to leverage any reuse from the library. Where-as just* a library, means that it uses the existing known mechanisms of whatever language you use for code reuse, like simple function calls for example.

seancorfield05:06:48

One of the few commonly-used libraries in Clojure that might be loosely categorized as "framework lite" is Ring, because it plugs in "above" your application code and it calls your functions. But that's a bit of a stretch given that you are specifically giving it a function to call.

didibus05:06:07

Ya, to me, it boils down to two things: 1. Is it at the application level? Does it take over your whole application? Or like Sean said, is it above your application? 2. Does it use non-standard and custom configuration and extension mechanisms? As opposed to using common language features.

8