component

Lambda/Sierra 2025-10-18T17:38:54.202389Z

Hey, it's me. I'm thinking about https://github.com/stuartsierra/component/pull/76, so you can do (with-open [system (start system)] ... in tests.

👍 2
1
1
🇧🇷 1
❤️ 3
2
Lambda/Sierra 2025-10-25T16:17:49.083369Z

This is now available in release [com.stuartsierra/component "1.2.0"] https://hachyderm.io/@lambdasierra/115435699727454025

1
🎉 6
seancorfield 2025-10-28T22:00:43.514689Z

Just upgraded to this at work -- it allowed me to switch a lot of code that looked like this:

(let [sys (component/start ...)]
  (try
    (do-something sys)
    (finally
      (component/stop sys))))
to just this:
(with-open [sys (component/start ...)]
  (do-something sys))
Thank you!

💜 1
seancorfield 2025-10-28T22:02:50.765869Z

Except that now I have reflection warnings from a lot of those: Reflection warning, ws/batch_jobs/appleappstore.clj:24:3 - reference to field close can't be resolved. Presumably component/start can't type hint its result to be Closeable since not all startable things are Closeable.

Lambda/Sierra 2025-10-28T22:13:50.868769Z

Yeah, I tried type-hinting. You can see my experiments in the https://github.com/stuartsierra/component/commits/component-1.2.0/.

Lambda/Sierra 2025-10-28T22:14:33.682999Z

I find that with-open often requires ^Closeable type hints in practice.

seancorfield 2025-10-28T22:17:27.366689Z

My approach in next.jdbc: https://github.com/seancorfield/next-jdbc/blob/develop/src/next/jdbc/connection.clj#L278 and https://github.com/seancorfield/next-jdbc/blob/develop/src/next/jdbc/connection.clj#L318 -- nasty but it avoids type hints in user code 🙂

seancorfield 2025-10-28T22:18:42.947679Z

(esp. since next.jdbc supports Component without depending on it)

Lambda/Sierra 2025-10-29T16:11:42.918759Z

I suppose one could also do something like

(defn closeable ^Closeable [object]
  (assert (instance? Closeable object)) 
  object)
but that's basically just type hinting with extra steps 🙂

👍 2
Lambda/Sierra 2025-10-31T00:11:47.293299Z

Or you could replace with-open with your own macro that calls a more generic close function.

🤔 1
seancorfield 2025-10-31T00:54:46.008789Z

I was over-aggressive with some of my refactoring to use with-open calls and found several "systems" at work that are not actually SystemMap and therefore not Closeable so I had to back off. Having explored this in production code, I'm not sure it's really a good change since not every started Component is compatible with with-open (i.e., not Closeable) and it makes for some fairly inconsistent code. I might well create some with-* macro to paper over the inconsistency, since I don't really want to "close" a Component, but I do want to automatically stop a Component.

seancorfield 2025-10-31T00:57:28.837029Z

Maybe a with-start macro that automatically calls both start and stop under the hood...?

2025-10-31T00:58:09.319959Z

with-lifecycle

seancorfield 2025-10-31T01:03:39.333879Z

Yeah, I saw your suggestion earlier and liked it but didn't want to @ you at this point, 20+ messages into the thread. But, yeah, with-lifecycle to call start and stop makes a lot of sense to me now, having tried with-open and decided I don't like it.

seancorfield 2025-10-31T01:07:09.913819Z

me sets reminder to create JIRA ticket at work tomorrow to revisit the Component 1.2.0 upgrade work I did a few days ago 🙂

2025-10-31T01:39:02.815129Z

A potentially interesting quirk is stop returns the stopped system, which depending, you might want in theory you could start it again, or inspect it to or something. That seems like it would be pretty niche though.

👍🏻 1
2025-11-03T16:00:24.361939Z

huh! nice! 😄 thanks @stuartsierra !

2025-10-18T17:46:27.564719Z

Have you considered adding a with-system macro to component? One of my favorite changes in component since I have been using it is the metadata protocol support for Lifecycle, allowing using plain maps as components. While the system map is not exactly the same thing, it does feel sort of like a step in the other direction to add more methods to it.

2025-10-18T17:47:09.323149Z

Maybe with-lifecyle

Lambda/Sierra 2025-10-18T18:09:30.306419Z

that's what this is for

lukasz 2025-10-18T18:12:08.252209Z

I've been doing something like this in smaller apps so yes +1 to this

2025-10-18T18:20:15.811669Z

does this work with extend-with-metadata system maps?

Lambda/Sierra 2025-10-18T18:27:17.230779Z

If you have a SystemMap containing components that implement Lifecycle via extend-with-metadata, then yes this still works. https://github.com/stuartsierra/component/blob/87ddaafa587b657af6b1191576875a933c0d0271/src/com/stuartsierra/component.cljc#L178 is a type defined in the Component library, not usually something you would implement yourself. If you want to implement your own system map type, then you would have to define it to implement Closeable. As far as I know, you cannot do that with extend-with-metadata because Closeable is a Java interface, not a Clojure protocol.

👍 2
Steven Lombardi 2025-10-18T18:58:27.348069Z

Yes please. We roll our own thing for this in tests and I'd be happy to get rid of it.

Steven Lombardi 2025-10-18T19:00:25.442619Z

And I'll state the obvious, just in case it's not obvious... ...calling .close on the system map would be equivalent to calling component/stop correct?

Steven Lombardi 2025-10-18T19:00:57.973889Z

The one caveat being you won't get the updated system map back because .close is void I believe.

Steven Lombardi 2025-10-31T19:38:04.286459Z

Curious Sean, what are the types of your non system map systems?

seancorfield 2025-10-31T19:43:26.433739Z

Some are plain records (that implement Lifecycle). Some are hash maps with start/`stop` provided as metadata. Some are data that have no start/`stop` -- which means the defaults are used that are identity. This is most common in tests for individual "small systems".

seancorfield 2025-10-31T20:06:01.639599Z

@hiredman Like so:

(defmacro with-lifecycle
  "Starts and stops a component system around the body."
  [[name expr] & body]
  `(let [~name (component/start ~expr)]
     (try
       ~@body
       (finally
         (component/stop ~name)))))
(59 references to this at work so far)

Lambda/Sierra 2025-10-31T20:10:02.394309Z

no nesting?

seancorfield 2025-10-31T20:13:42.579709Z

Dependencies? A la component/using? Doesn't require a system map -- only something that can carry metadata. system-using works with a hash map.

seancorfield 2025-10-31T20:15:38.069869Z

We have 41 instances of component/using, 16 component/system-using. 33 calls to component/system-map. 141 calls to component/start.

Lambda/Sierra 2025-10-31T21:06:59.472469Z

no I meant multiple bindings in your with-lifecycle, like with-open supports multiple bindings by recursive expansion

seancorfield 2025-10-31T21:19:25.779489Z

Ah, no, I didn't bother since I think there is only one place in our codebase where we start'n'stop more than one component for a particular piece of (test) code.

👍 1
2025-10-31T21:29:25.452559Z

I want to try to get some combo of components + closeable maps working hehe

2025-10-31T21:29:54.175919Z

https://github.com/piotr-yuxuan/closeable-map this is very interesting for me but we need the tree of deps

2025-10-24T16:31:20.825329Z

Nice, thanks @stuartsierra :)))

2025-10-24T16:43:20.811909Z

it was me haha

Lambda/Sierra 2025-10-24T16:57:49.270229Z

Ohai! @d.ian.b

2025-10-24T17:05:27.663219Z

thanks for the attention and embracing the suggestion 😄

💜 1