Solvedclj kondo Convention for necessarily required but not explicitly used namespaces

Ideas for expressing: this namespace is necessarily required but not explicitly used (loading specs, loading a foreign lib, multimethods, etc).

Problem

The problem is that some tooling warns or even removes required namespaces that are not explicitly used in the code. However, sometimes these namespaces are still used for registering specs, multimethods, etc. So there should be a way to say: we need these namespaces regardless of explicit usage.

Example:

(ns foo
  (:require [foo.specs]))

Here specs related to foo are loaded, but the namespace foo.specs is not used explicitly.

Related issues with earlier discussions:

Ideas:

  1. single symbol libspec

Example:

(ns foo
  (:require [normal.ns]
             my-side-effecting.ns))

Pro: simple, no clutter
Con: with this approach: there might be others that are accidentally also unwrapped and not reported.
Con: doesn't work for unused java imports (but these don't cause side effects anyway).

  1. Attach metadata ^:keep on a vector in which the ns name is wrapped
(ns foo
  (:require ^:keep [my-side-effecting.ns]
            [normal.ns :as n])
  (:import ^:keep [java.lang String]))

(n/foo)

Pro: works for requires + java imports
Pro: less accidental than 1
Con: breaks vertical alignment. However, it seems clojure-sort-ns already respects metadata:

  (:require
   ^:keep [bar.specs]
   ^:keep [foo.specs]
   [another.namespace.a]
   [another.namespace.b]))

so maybe this wouldn’t be a problem, since ‘keeped’ libspecs go on top anyways.
Also you can use a newline after the metadata to fix the vertical alignment.

Con: you always have to use a vector to place metadata on, since CLJS allows strings as namespace names in :require. This is not really a con, since this is already encouraged style in how to ns.

  1. Empty :refer vector
(ns foo
  (:require [my-side-effecting.ns :refer []]
            [normal.ns :as n]))

(n/foo)

Pro: less clutter than 2
Pro: less accidental than 1

  1. Use a comment or uneval (this has been my approach so far in earlier projects)
(ns foo
  (:require [my-side-effecting.ns] ;; keep
            [my-side-effecting.ns2] ;; #_keep
            [normal.ns :as n]))

(n/foo)

Pro: less accidental than 1
Pro: better alignment than metadata
Con: clutter
Con: comments might not be seen by all tooling at the moment the AST is processed (clj-kondo included)

  1. Wrap in list instead of vector:
(ns foo (:require (foo.specs)))

Pro: no clutter
Con: might be accidental

52 Answers

✔️Accepted Answer

Another option is:

When there is no :as foo or :refer [foo] the tooling MUST assume that this namespace is implicitly used?

I think this works for 99% of my "implicit requires"?

Example from a file that was in front of me right now:

Screenshot 2019-06-13 15 23 35

The implicit requires are dre.yada.html and dre.yada.xml which are exactly the only ones that do not have an alias or a :refer.

Other Answers:

I like the metadata idea, because that's what it is—metadata on the require for other tools to use. It's explicit, and doesn't conflate existing patterns with implicit meaning.

Why not keep "side-effecting" requires outside of the ns macro ?
Linters could still clean the ns form and leave explicit requires by themselves.

Most people see the ns form as declarations of stuff to "compile" your code, so coming from others languages it feels natural to tidy those declarations.

But when you want "side-effecting" requires, it is usually to set some state for your running program. It seems to me, that it should live outside of the ns form.

Instead of adding new meta-keys convention on top of the language for tooling, maybe we just need to advise (in clojure style guide for example) the explicit usage of require out of the ns macro for runtime side-effects?

@zane both clj-kondo and joker already support this in their config files (:ignored-unused-namespaces in joker and :unused-namespace -> :exclude in clj-kondo). I do like this approach because it keeps the code uncluttered. I also think that it's usually a good idea to have a more elaborate comment like ;; required for XXX multimethods rather than just ;; keep, and if there is already a comment, additional signals like ^:tooling/keep are unnecessary from readability point of view.
^:tooling/keep might be a good option though (in addition to config files).

The newest clj-kondo already supports this feature.

Related Issues:

13
clj kondo Convention for necessarily required but not explicitly used namespaces
Another option is: When there is no :as foo or :refer [foo] the tooling MUST assume that this namesp...
25
metabase Question mark in SQL query (postgres JSON operator) interpreted as prepared statement param
@agilliland ? is the Postgres JSONB operator to check whether an object contains a given key ...
21
metabase Connect to MongoDB error: Connection to ... successful, but could not connect to DB.
I was having the same issue and this solved it: I'm running a docker image of metabase and a separat...
20
metabase Unable to connect to MongoDB Atlas Cluster
Receiving the exact same error message: com.mongodb.MongoTimeoutException: Timed out after 3000 ms w...
17
metabase Add a template tag to use already defined queries
It would be great if we could pass variables to nested questions: At its simplest ...
16
babashka clojure.core.match
Just chiming in to say I'm also interested in using clojure.core.match with babashka! ...
11
cider cannot restart repl after killed it
I had the same issue I don't know Emacs Lisp very well Use the template below when reporting bugs Pl...
9
metabase Connections can not be acquired from the underlying database!
had this issue yesterday when upgrading from 0.30.* to 0.32.8 and fixed it by adding trustServerCert...
7
metabase Hide x-rays on homepage (alternatively: make it possible to select which database is shown)
I would like to be able to hide/disable x-rays for a different reason - they may result in expensive...
3
status react 'RCTBridgeModule.h' file not found
I had this issue and solved it by doing: rm -r node_modules/ rm -r ios/Pods npm install cd ios && po...
13
shadow cljs Expose a cljs prepl via socket
2.8.59 has initial prepl support but it probably still needs some tuning You configure it via :prepl...
61
okhttp Android O StrictMode: Untagged socket detected
there would be negligible value to having such a tag Suppose a dev team sets penaltyDeath() for all ...
26
truffleruby Support the Nokogiri gem
We now support Nokogiri but only with a shared installation of libxml2 We need to support Nokogiri p...
20
truffleruby Support the openssl standard library
openssl is now enabled by default on master We're now merging this into the next GraalVM release. ...
20
okhttp java.io.IOException: stream was reset: CANCEL and PROTOCOL_ERROR
The same problem happened in Http2 the okhttp version is 3.8.0 does it have a solution? ...
19
okhttp isCleartextTrafficPermitted() fails on OpenJDK 8 + Robolectric
I was able to get the test green Here's what I did: Change to using OkHttp-3.3.1 The project was usi...
17
okhttp Unable to extract the trust manager
I experienced this error while using a custom SocketFactory I realized I didn't add all the necessar...
16
okhttp OkHttp3 - IOException: unexpected end of stream on okhttp3.Address@9d7c59b5
Here's your fix: The error occurs when OkHttp try to reuse a connection that is in FIN_WAIT2 state i...
16
okhttp 3.14.1 interceptor regression
@ysy950803 close the response before replacing it with the chain.proceed inside the while loop Thank...
12
okhttp AssertionError at AsyncTimeout.java:101 for some android 4.4.2 and 4.4.4 devices
We at @StudioSol had the exactly same problem Hey okhttp I've been confused with this AssertionError...
277
eslint Unexpected block statement surrounding arrow body arrow-body-style
If you wrap the object in parentheses it will parse correctly and the rule won't error: ...
256
pylint cv2 module members are not recognized
On VScode: CTRL + Shift + P Choose Preferences: Open Settings (JSON) Add this line into JSON file: p...
106
eslint config standard Error: Cannot find module 'eslint-config-standard'
@FNGR2911 I know the reason now because the es-lint I implemented is global installed so it looks fo...
83
pylint logging-format-interpolation for f-strings
Please not! f-Strings are more readable and fast Pylint will warn against using .format and % when l...
82
eslint Arrow functions: "Parsing error: unexpected token ="
You should add babel-eslint as parser. Tell us about your environment ESLint Version: 4.19.1 Node Ve...
81
eslint require-atomic-updates false positive
I would say that if nothing else error message is pretty misleading That is simply not true ...
79
eslint "Cannot read property 'type' of undefined" after upgrading to 4.14.0
I apology for the inconvenience We have found a bug in babel-eslint's new logic that I added ...
79
tslint Indent rule not reporting or fixing indent size violations
I'm experiencing the same issue The rule below will catch tabs being used instead of spaces but won'...
69
lint staged Build typescript on commit
hi I know this is an already closed issue but I still ran into it I'm trying to rebuild my typescrip...
68
eslint no-return-assign behavior changed with arrow functions
No idea if that is important for this but using brackets also suppresses the warning although it's s...
67
ale pylint import problem with modules in the same folder
To leave this here I found a workaround modifying the init-hook of.pylintrc: However some general so...
62
pre commit python3.7: command not found
Just adding this here for anyone that comes across this issue When you create a virtualenv using for...
61
lint staged No staged files match src/**/*.{ts,tsx}
I solved my problem I had a space in between ts and tsx change in .lintstagedrc.json from *.{ts tsx}...
58
pylint Problem with Flask-SQLAlchemy, cannot find valid and existing property in SQLAlchemy object.
I find an elegant solution here: https://stackoverflow.com/questions/28193025/pylint-cant-find-sqlal...
51
mypy How to accept dicts with extra keys?
I would like this issue to be re-opened I think extra_keys is important to have The current solution...
50
tslint no-implicit-dependencies: Support path mapping
This rule does not work when we use alias for our own source code (not to import from npm packages) ...
49
standard Specify eslint-env globally?
Put it into .eslintrc file in your /tests folder like this. Is there a way to set ESLint environment...
46
ale Disable linting for select files
@mark-westerhof You should now be able to disable linting for files like so. I currently have some f...
43
standard Cannot find module 'babel-eslint' (eslint/undefined)
Doing npm install babel-eslint --save-dev seems to fix the issue as well. Using this as a local depe...
42
SublimeLinter env: node: No such file or directory
I've added this to SublimeLinter.sublime-settings and problem gone: /usr/local/bin/ is my Node locat...
41
lint staged lint-staged ignores tsconfig.json when it called through husky hooks
Similar issue with tsc Passing files AND project config is not possible When invoked from husky ...
40
eslint eslint-disable-next-line does not work in html portion of .jsx files
eslint-disable-line and eslint-disable-next-line are supported in only line comments ...
36
tslint failing when running locally
I just ran into the same issue.. was using YARN Turns out that the issue for me was that I at some p...
36
tslint No valid rules have been specified
I've found a possible solution: If you're using setting allowJs: true in tsconfig.json it will try t...
33
pylint --fail-under flag
@PCManticore @brycepg Please consider re-opening this This is a useful feature coverage also has sim...
29
isort Cannot import name 'SortImports' from 'isort'
This also affects pylint: Hi I recently updated ISORT using Poetry on a clean virtualenv I'm getting...
29
tslint Support linting vue/html file
Some more news here? 🤙 Feature Request TSLint version: 4.3.1 TypeScript version: 2.1.5 Running TSLi...
29
mypy Dynamic base classes are not handled
For anyone who comes across this via the original report a simple way to address sqlalchemy/mypy iss...
28
tslint Compiler option 'extends' requires a value of type string
@StanLee12 what are the exact CLI arguments you're using? I think you might be using the same invali...
27
lint staged Add better support for partially staged files
Why not simply temporarily doing git stash -k? See react-boilerplate/react-boilerplate#1064 (comment...