Fork me on GitHub

Is there some other name or fundamental idea for Software transactional memory, but in a single threaded context?


Aka a bunch of mutable refs that you can mutate in some local context and then later commit; but the context would be like a single event loop, not a thread


no idea as for the naming, but I have implemented this for a production SPA in cljs if that's any useful!


That’s interesting. What was your use case?


this was an Om + core.async app. IIRC it was possible that multiple go blocks would mutate the same data concurrently, causing inconsistent state


Is it open source by chance, or any references that could help me understand the implementation?


not, unfortunately


I'm not sure if that'd be the same thing in a JS context. JS has this "run to completion," uninterruptible semantic where even exceptions don't stop things in external contexts. IIUC, STM requires some interruptability. You could maybe build an interruptible runtime, on top of go loops, and then dispose of contexts as they become invalidated. But I'd bet you'd be introducing a lot of overhead in a single threaded thing. If you combined an interruptible go-loop runtime with webworkers and js/Atomics.notify, you might be able to do an STM over CLJS, IMO.


yeah, I actually posted a follow-up in #clojure with an example of what current thinking is:

Adam Helins06:05:37

More of a FP question, is there a specific name for a tree whose nodes towards the root are sorted and nodes towards the leaves unsorted? Thus each leaf having essentially 2 paths, a "horizontal" one providing ordering and a "vertical" one providing hierarchy?


I am not clear on what you mean when you say a tree whose nodes towards the root are sorted.


One definition of a tree is that every node except the root has exactly one parent. So one interpretation (perhaps not what you mean) of "nodes towards the root" are "parent nodes", but if each node has exactly one parent then having "sorted parent nodes" doesn't make much sense, if there is only one node that is sorted.

Adam Helins07:05:53

Well, here is a small example:

(sorted-map 0 (sorted-map 10 {:a {:b :leaf-1}})
            5 {:c :leaf-2})
We can say that :leaf-1 has as horizontal path [0 10] which provides ordering or prioritization if you will, and a vertical path [:a :b] which provides a hierarchy. It would pop before :leaf-2which has a horizontal path [5] (and a vertical path [:c]which does not participate in the ordering). I am using such a datastructure for a discrete-event engine I am building. I figured it probably exists but cannot manage to find a name.

Adam Helins07:05:17

We can say that a horizontal path represents time while a vertical path represents space.


Do you mean that if you start at any leaf node, some leaf nodes have no sorting relationship with their sibling node. An unsorted leaf has a single parent node, and it might also be unsorted with its siblings, or it might be sorted. If it is sorted, then that node's parent will be sorted, and its parent, and so on all the way up to the root node.


So you could draw such a tree where the root and some set of descendants that are all 'connected' are sorted, but further away from the root and they are all unsorted?

Adam Helins07:05:44

I believe a simpler way of putting it is that if we take the full path of a leaf such as :leaf-1, which would be [0 10 :a :b]in this case, then one garantee I have is that the first items in that path represent order, while the last items specifically not. Relative to the same root, :leaf-2at full path [5 :c]has only one item specifying order. But my garantee holds, first order, then unorder.


By the "full path of a leaf" do you mean the path of nodes starting at a leaf node, proceeding to its parent, then grandparent, etc. ending at the root? And every such path has zero or more nodes that 'represent order', followed only by nodes that do not represent order.


If so, I have not heard of a name for a tree with such a structure.

👍 4
Adam Helins08:05:46

Yes exactly! Although, to be more precise, I build a path by starting at the root and going until I reach a leaf thus cannot continue. The idea is not that complex but it has neat properties.

Adam Helins14:05:16

@U0CMVHBL2 In case you are curious, I organized it as a separate lib:


Does anyone know of a good short video that illustrates the power of repl-driven development? Trying to introduce this concept to a friend.


There's Sean Corfield fixing a bug in core.memoize: But TBH REPL-driven-dev is something that needs to be experienced to be understood. Edit: Fixed a typo.

🔥 4

oh yes this is awesome!! i agree with you about it being something you need to experience to understand

💯 4

I've always liked this one too and it's quite short:


+1 for both of Stu's videos. Also his Conj 2018 introduction to REBL is very useful as background thinking for RDD (I just rewatched it yesterday).


And thank you for mentioning one of my Atom/Chlorine/REBL videos. I'm planning to make a couple more "soon". I've been trying to figure out a way to show a dynamic dependency loading workflow, so you can start a barebones REPL and then add libraries and build a web app without leaving the editor/REBL or restarting anything.

❤️ 4

I got that all working yesterday so it just needs a bit of polish before I record it.

💯 12

Awesome! I've just started to tinker with the add-lib branch of tools.deps.alpha myself.


you know, I saw a video of someone very fluidly iterating and building up an opengl driven app (in Common Lisp), I wonder :thinking_face:


granted, I didn't watch much, I don't wanna speak too soon


Oh that would be cool too! doesn't need to be clojure i guess. there's this: but it's technically not repl-driven development? I think it shows how awesome a quick compile-execute feedback loop can be


Complexity is this weird game where your program is holding hands with two people holding hands with two people holding hands with two people, and you're busy trying to figure out who all is in this line so you can find out if there's a jackass that's going to pull everyone down Immutability is an example of playing this game with no arms I am drunk

❤️ 16
🍻 16

Any database I can immediately deploy (preferably with docker) and use through http for prototyping purposes? Something that would allow me to do POST /person {:name "John" :age 24} and GET /person/[:id] or similarly simple


a RESTful layer on top of Postgres


There's even a clojurescript example:


Hi all . Does anyone write hiccup code on Roam ?

eccentric J20:05:36

My friend who loves Python was horrified by this

😲 4
metal 4

To be fair, code like this shouldn't even exist:

some_string = "wtf"
some_dict = {}
for i, some_dict[i] in enumerate(some_string):
    i = 10


I would enjoy a "wtfclojure"

rich 16
😎 4
eccentric J02:05:46

I'm trying to think of an example for wtfclojure. I don't want to say there's none but at the very least I'm not experienced enough to be aware of any. I'm assuming the criteria would be if your expectation for how it parses is different than what it does?


It's hard to assign a boundary. E.g. about 70% of the wtfpython examples made me think: "Yeah, because that's how it works." But that number is probably near 0 for someone that have never used Python.


Yeah, about half of the Python ones were clear to me because I know what's happening under the hood. I'm sure we can concoct much more puzzling pieces of code with dynamic bindings and macros in Clojure, but with great power comes great responsibility ¯\(ツ)


I bet you could come up with a number. I can think of some general things like: • needing to add indirection via vars when binding to values at top-level (e.g. (def foo bar) ) to allow re-defing at the REPL • case not respecting bindings in matches • hashmaps maintaining insertion order < 8 values • chunked realization of lazy seqs + side effects


all of them are easy to steer clear of once you know what's going on, but if you have a naive model of how Clojure works then you might be surprised by them

eccentric J06:05:46

> hashmaps maintaining insertion order < 8 values That one did get us the other day but it was only a problem because we needed to clj->cljs and cljs->js regularly due to the js lib we’re working with.


A small one: the number literals are long by default, not integer.


There are some in ClojureScript, mostly because of the way JS equality works. On some cases, NaN appears duplicated in sets or as map keys, but keep being a single one when the collection grows

Gleb Posobin21:05:34

I am writing an SPA, what's the recommended authentication protocol? I wanted to use signed JWTs with an access token and refresh token, but not sure what are the recommendations for that. Apparently it is not safe to store the refresh token on the client due to XSS? But what alternative is there, I can't just use the access tokens. Also, afaiu the access token has to be accessible to the code — I can't just send it as a cookie to the server since then CSRF can happen, but some articles recommend exactly that. I wanted to minimize the requests to the DB so didn't want to just store a session id on the client.


The refresh token is supposed to be kept secret only to the oauth client (which would be your server), but a good trick is to just encrypt the refresh token and put it in a cookie, so that only the server can decrypt it and use it. Keycloak-gatekeeper does it this way


You do need to have csrf protection though. I think with regard to xss it's not just about the refresh token, even just putting the access token on the browser would make the set up weak to xss, without csrf protection


Oh wait actually, depending on the kind of xss, all bets are off even with csrf protection


I'd say the way to handle this is to add csrf protection and also make sure the site is safe from xss, because even if you used a session-id, with xss the attacker would be able to pick up the session id and make a request anyway, and pick up the csrf token with it, so...


I've used OpenID Connect in the past to good effect.


For authorizing users within a browser-based application, the best
   current practice is to

   o  Use the OAuth 2.0 authorization code flow with the PKCE extension

   o  Use the OAuth 2.0 state parameter to carry one-time use CSRF

   o  Recommend exact matching of redirect URIs, and require the
      hostname of the redirect URI match the hostname of the URL the app
      was served from

   o  Do not return access tokens in the front channel


It should be noted that I landed on using OIDC not because it was the simplest way to do authentication but because of the single sign on capabilities and identity federation use cases from customers, so ymmv.


me too! I used keycloak to handle all that, and keycloak-gatekeeper is awesome for quickly putting something working together

Gleb Posobin13:05:12

Is xss the only problem with the following flow? 1. On login, user gets a signed JWT access token, and a session id refresh token. Browser stores the access token in the local storage, and the refresh token is stored in an httponly cookie with same-site=strict option. 2. On api requests, the client sends the access token in the Authorization header of the request, and the server uses the access token for auth. This prevents CSRF. 3. When the access token expires, the user can request a new one by sending a request to /get-new-access-token, the server verifies that the refresh token in the cookie is valid and generates a new signed JWT. CSRF can't (?) happen here because of same-site=strict: a request from another service won't have the cookie attached.

Gleb Posobin13:05:43

OIDC seems complicated...


Yes OIDC is somewhat complicated. How do you manage the identities?


@U8P40TFSR yeah keycloak is a strong product for sure.

Gleb Posobin16:05:19

@UPGJNT3UY what do you mean by "manage the identities"?


@UQ4RJ22EA I mean how do you add / remove users?


Or what defines the set of people that should be able to authenticate?

Gleb Posobin17:05:48

They sign up for the site.

Gleb Posobin17:05:41

It's just a website, anyone can sign up and use it.


in (2), CSRF can still happen. CSRF means some attacker gets the authenticated user to do something (e.g. transfer the attacker money), on the original site itself, so using the samesite stuff doesn't protect against CSRF.


it's also vulnerable to CSRF in (3), CSRF isn't about stealing a cookie protected with same-site=strict


actually, @UPGJNT3UY is right, if your site is alone and you don't plan to share this sign in across other apps, or you can trust the main client-facing service to manage all the calls to backend services, it might be easiest (and safer) to just build authentication using sessions (CSRF protection still needs to be in place, code still needs to be reviewed to ensure no XSS)

Gleb Posobin03:05:59

How can CSRF happen in 2 if I am not using the cookie but sending it in the header? To send the authenticated request the attacker would need to know the access cookie.

Gleb Posobin03:05:38

I understand that CSRF is not about stealing the cookie, but iiuc it's about sending a request to my endpoint from another site. Such request won't get authenticated in 3 because the cookie is same-site=strict, so it won't get attached to a request initiated by an external site.


The request is initiated by an external site to your site, and that request to your site will have the cookie attached. If you're a bank, the request could be POST https://bank.example/transfer?to=attacker. The token from bank.example will go to bank.example - it is the same site! And the money will go to the attacker.


With csrf protection, the legit bank site could have some token set in the page contents, and the legit JavaScript call will post the same token back together with a token in the cookie (which the legit JavaScript doesn't have to read), because in a legit setup the two tokens are the same


If the attacker tries to send some request through the browser to bank.example, the token in the cookie goes with the malicious request, but the attack won't have access to the token in the page so the tokens won't match and the csrf protected endpoint is supposed to block the request


This is sort of orthogonal to the same site = strict setting. Since cookies belonging to a host and path always get sent to that host, regardless of how strict the setting is

Gleb Posobin20:05:57

In (2) the cookie will be attached, yes, but the server is looking at the Auth header and is ignoring the cookie! So if only the cookie is present, server won't authenticate the user. Third-party site can't set the header correctly because they need to know the auth token from the cookie for that. No, cookies with same-site=strict don't get sent with requests initiated by third-party sites.

Gleb Posobin20:05:18

That's the whole point of same-site field...


oh! sorry i misunderstood the same-site field!! thanks for explaining. in that case, then we should safely be able to put the access token in the cookie...? putting the access token in the cookie saves the trouble of having to read from local storage and sending it using some library on the client side, right? since cookies are automatically sent along with every request

Ramon Rios21:05:39

I do clojure for a while in a daily basis, but not startup a project from 0 and i want to let some stuff on github for a kind of portfolio. Is there any place that i can get ideas for create a portfolio?


You want to advertise your Clojure experience, perhaps for showing to potential employers what you have done?


If yes, and you have contributed to open source Clojure projects with their commit history public on Github or similar sites, you can link to each of those in a list, and provide some description of the changes you have made.

Ramon Rios21:05:01

Good Andy. Thank you

Ramon Rios21:05:38

On my case, i haven't contributed yet. But i can look some open source projects to colllaborate