Fork me on GitHub
#clojure
<
2020-02-25
>
Parenoid04:02:23

Regarding all the earlier discussion of an npm style deps tool, https://github.com/hagmonk/find-deps is perfect. At least as described, it does all the obvious things one wants, at least if you're someone who just wants the most recent version of a dependency (or any version you specify) into your project, and also your deps.edn if you desire; it also lists available versions. Long overdue.

pinkfrog08:02:13

I added this line in dependencies: [thheller/shadow-cljs “2.8.83” :scope “provided”]

pinkfrog08:02:39

however, after uberjar, the jar file still contains “shadow/xxx” files.

vlaaad08:02:22

huh, clojure.main/repl does not support :repl/quit ? For some reason I thought it did

vlaaad08:02:53

got too used to using prepls that support it..

wotbrew13:02:43

Does anyone know if its possible to watch for new vars being defined or syms being interned in an ns, i.e is there some kind of hook I can use? I could poll the ns, but I'm looking for a callback ideally.

dharrigan13:02:11

would this help?

dharrigan13:02:26

but that's probably for existing vars

wotbrew13:02:28

Works for existing vars

dharrigan13:02:37

sorry 😞 🙂

wotbrew13:02:53

It'd be handy to be able to hook into new namespaces and vars being created, being the introspectable 'stuff' of clojure programs, I think some very cool tooling would be possible - that could be more responsive and applicable in more instances if you could get in at a low level and watch for these changes. In particular catching definitions made on any thread, perhaps in loops and other dynamic contexts (even if not considered good practice)

rickmoynihan09:02:44

I’m not sure you need to poll, or to require watches to be added to clojure itself. In practice most tooling is going to be written to work over a network REPL typically one of socket-repl/prepl, nREPL, or unrepl. In any of these REPLs you should be able to intercept/wrap the call to eval and inspect it for calls to def etc and then hook on that to compare the before/after states of the namespaces. In practice because of macro’s and hooking (def-mything ,,,) forms you may need to either macroexpand forms yourself before evaling, or perhaps just catching the return value of forms, and if it’s a var re-running your ns difference check. This will obviously mean each repl will need its own plugin, but you could just target the repl of your choice — or move the core logic into a library of its own and share it across repl “plugins”.

rickmoynihan09:02:28

I say “plugins” because with repl’s like socket-repl/prepl I’d expect you’ll need to wrap the repl yourself rather than plugin to it.

rickmoynihan09:02:26

Obviously there are limitations to this approach, in that you’ll only hook things that are done through your interface — but in practice I’m not sure that’s a deal breaker; as most workflows people just use one repl type, typically whatever their editor supports.

wotbrew09:02:11

Hmm interesting idea

rickmoynihan09:02:11

it’s not that hard to do either

rickmoynihan09:02:49

what tools were you thinking would want to know when vars are created?

wotbrew10:02:15

I've got this idea for a tool that helps you navigate globals in your program - and allows you to search / inspect etc. Cross-over with IDE's / REBL. Its a bit amorphous, I like the idea of exploring 'living system' style development, think small talk. Basically your unifying the object space of your program and ensuring you've got a good handle on it - vars/namespaces are one aspect, things like threads and components are another part of it. Its just an idea and I want to experiment a bit and see what you could do. Its a vague set of ideas at the moment and maybe will go nowhere - one thing in my mind is whether it being a repl driven library is actually better than just developing ide plugins...

rickmoynihan10:02:02

:thumbsup: That’s the sort of thing I thought you’d probably say 🙂 I’d suggest also though that for that you possibly don’t need it to be live… Why not start with a sidecar swing UI (maybe javafx if you want to get fancier — but complicate the install), that you start like (require '[ns-explorer.sidecar :as sidecar]) (sidecar/start) And it just pops up the swing frame at that point with a snapshot of the current state… You could have a refresh button first… then work to remove it if you really wanted… though I think a snapshot of the state at the point you fired up the window would be enough… not sure it needs to stay open all the time and be live.

wotbrew10:02:45

The reason I'm thinking about hooks or fast invalidation is for incremental indexing

wotbrew10:02:00

I have many indexes in mind

wotbrew10:02:15

But I agree it could work ok for small projects

wotbrew10:02:23

^^ also it really isn't about namespaces and vars, they are just examples of objects you may be interested in. There are also mbeans / jvm objects / threads, thread groups, components, high level state etc. I think we can look at the idea of universal search, addressability, query, + datafy/nav from all roots (not just taps / repl evaluation)

wotbrew10:02:32

Hopefully it makes sense why I might want something as unholy as definition hooks

rickmoynihan11:02:53

Yeah it makes sense, though I doubt you’ll get what you want 🙂 — incidentally introspecting many of those other objects can be done through jvisualvm and other similar tooling which works quite well… though I certainly see the desire for a more clojure specific repl based tool.

wotbrew12:02:44

I'm always looking at my beans me

zilti13:02:08

That sounds like a terrible thing to do

wotbrew13:02:57

Even for dev tooling? I mean come on.

Alex Miller (Clojure team)13:02:45

There is no hook, you’d have to poll the namespaces

zilti13:02:49

Tooling can afford to poll, though.

zilti13:02:21

And if you want to know the value of a variable in a certain thread, well, that is what debuggers have been invented for 😉

wotbrew13:02:05

I think I would start with polling but clearly its a limited approach in terms of how well it can scale to larger programs, and more 'esoteric' uses of namespaces and vars.

wotbrew13:02:31

Obviously I'm not recommending people do things like dynamically def in macros for intern tables and such in all cases - but I bet there are applications and libraries that do it.

wotbrew14:02:16

^^ I may well be barking up the wrong tree, just looking to explore some ideas - I imagine the potential for misuse/abuse of such a feature would be quite high - but would be handy for what I'm trying to explore.

pinkfrog15:02:47

how to avoid passing the state across a long invocation chain of functions ?

hindol15:02:24

Can you share an example?

pinkfrog15:02:03

For example, I am writing a web-app handler. Upon receiving a request, the handler will invoke a sequences of functions and finally update the db. So, that web-app handler should store the db conn at first hand, so that it can pass the db conn information across the function invocation chain to the final one. Two concerns of this approach: 1. The initial handler would store too much information. For example, other than the db conn, it may need store other external resources information for different requests types. 2. Explicitly passings these information across a long sequence of functions invocations seems laborious and verbose. I am not aware of any better approach in FP (instead of OOP as in java, where methods can implicitly access the instances states).

dchelimsky15:02:20

> Explicitly passings these information across a long sequence of functions invocations seems laborious and verbose. Until you have to debug something and all of your arguments are right there. It's a tradeoff, but one that pays off in the long run in my experience.

8
jumpnbrownweasel17:02:05

@UGC0NEP4Y, if you're thinking in OO terms you might use a map that has the connection and other context info for the request that is passed as one param, and you could think of this as sort of an OO instance. Combining params into maps I think is common.

hindol17:02:06

It is analogous to OO actually. In OO languages you do X.Y(<params>), i.e. call method Y on object X. In Clojure you do Y(X <params>) . X is your state, which in OO languages is stored on the object itself. Here the function Y is not attached to any object, like OO, so it is inherently more re-usable.

hindol17:02:27

It becomes quite natural after some time.

p-himik17:02:49

Yep, it's pretty common to just create a single map (maybe a record if you know all the fields in advance) as a context and pass it around.

Avichal20:02:52

For Request Context, we have been using dynamic vars. The api handler gets called with some bindings. Any function that is called down the call chain just uses *var-name* to get access to the http request info if it needs to. Personally, it felt a bit weird to do so initially, I would rather prefer just passing around maps everywhere. But now that I am used to it, it works pretty well for us.

jumpnbrownweasel20:02:20

I strongly recommend not using dynamic vars to avoid parameter passing. Implicit params cause all kinds of problems. There have been many posts describing this, but I don't have the references handy.

12
jumpnbrownweasel00:02:19

Thanks @U0ENYLGTA I'll add that to my notes.

Avichal07:02:05

Thanks, for sharing

dpsutton15:02:10

i had no idea you could do this:

(doseq [:let [x (range 3)]
        y x]
  (println y))

🧠 8
ghadi16:02:03

@dpsutton doesn't mean you should 🙂

ghadi16:02:15

which part, the :let or the second binding?

dpsutton16:02:26

the let before the sequence part 🙂

dpsutton16:02:40

apparently for doesn't allow this?

Alex Miller (Clojure team)16:02:59

I think there's a ticket for that actually

Alex Miller (Clojure team)16:02:49

I have a hard time putting much priority on it

dpsutton16:02:36

i would not work on that either 🙂

dpsutton16:02:44

haha that's a low number 🙂

ghadi16:02:12

yeah, lol'led

ghadi16:02:53

I tried to rewrite doseq a long time ago and remembered these clauses being wild to handle

ghadi16:02:44

yeah... I left them as an exercise to the reader simple_smile

apbleonard22:02:17

Does it ever make sense to define and use a namespaced key only ever outside that key's namespace?

apbleonard22:02:02

Part of me thinks that perhaps the keys should first be "declared" in their home namespace, and used elsewhere ... but another part of me thinks that's not "open" enough...

shaun-mahood22:02:14

@apbleonard I tend to use namespaced keys more in relation to some element rather than an actual namespace - something like :email/address or :civic/address wouldn't have a real namespace it related to

🙂 4
apbleonard22:02:52

I'm sure I've seen folks recommending putting keys behind (namespaced) symbols in the past and I suppose this would achieve that goal (if it's a goal) ... but I think that hides the elegance of namespaced keys and their syntax, and the simplicity of what they are.

apbleonard22:02:06

@shaun-mahood Yes perhaps in my sleep deprived state I'm simply mixing the namespaces concept entirely... I suppose the namespacing of your information model does not have to map to the namespacing of your code 🙂

16
andy.fingerhut00:02:51

Alex Miller said in a semi-recent discussion on Slack that he sometimes calls the a.b.c part of the keyword :a.b.c/x a "qualifier" rather than a namespace. There need not ever be such a namespace created.

shaun-mahood01:02:02

Ooh, I like that - much better than “synthetic namespace” which I picked up somewhere

apbleonard17:02:29

Interesting ... I think going full Hickey on naming I would quibble with "qualifier" which sounds like an additional attribute (i.e. metadata) to an existing thing. The prefix here really is part of the name - itself defining the space of names - and so "namespace" is right IMO. It's just that then people conflate it with the space of names of symbols in your code 🙂

apbleonard18:02:27

I guess the handy double colon e.g. "::foo" syntax encourages this conflation, but then their are many times when your (e.g. library) code wants to reserve its own name for its own code purposes, and there it makes total sense to align the namespaces... e.g. ::spec/invalid

apbleonard18:02:13

On "qualified" ... perhaps it passed the hickey filter ... just seen this