Welcome! Please see the About page for a little more info on how this works.

+1 vote
in Syntax and reader by
edited by

Only lists carry location data, even though most non-primitives implement IObj. Is there a reason for this? Would there be interest in adding location data to all IObj objects at read time?

user=> (meta '(1 2 3))
{:line 1, :column 8}
user=> (meta 'abc)

1 Answer

0 votes

What problem are you trying to solve?

I would like to improve error messages by pointing directly at offending objects instead of pointing at the surrounding list. For example, in a `let` block, there can be a deeply nested symbol that doesn't resolve, and the syntax error will point at the `(let` location, not at the offending symbol:

    (let [{a :very-long-key
           b :another-long-key
           c :extremely-annoyingly-long-key
           {:keys [dddddddddddd eeeeeeeeeeee fffffffff]
            :as options}
          :final-very-long-key} d]

    ; Syntax error compiling at (example.clj:1:1).
    ; Unable to resolve symbol: d in this context

This could instead say `Syntax error compiling at (example.clj:6:30)` because that's where the `d` is.

Another example is hiccup syntax, a popular method for writing html primarily using vectors and keywords. Some libraries such as Reagent treat vectors that start with a symbol differently. If one of the symbols is misspelled, the surrounding call to `r/render` will be highlighted as failing instead of the specific symbol which can sometimes be 10s or 100s of lines below (as seen in some of the codebases I work on :grimacing:).

I can also see this being useful when making errors for unmatched delimiters. Right now, if you say `(some-fn ... [a b c)` and there's lines between the open square bracket and the closing round bracket, the error points to the closing round bracket. If all brackets carried location data, then the error could say "Syntax error reading source at (example.clj:N:M). Unmatched delimiter: ). Expected ] to match [ at (example.clj:X:Y)"
I forgot to mention that this would be helpful for macro writers as well, that they could use the location data on non-lists to write informative error messages. I occasionally see folks lament that macros throw away location data, and this would help improve that situation.
I am also very interested in this feature. I would like to use it in conjunction with `clojure.lang.Compiler/analyze` to find all usages of a local binding in a given Clojure form to, in a Clojure editor, highlight all such usages and give the user the possibility to rename the binding and all its usages.

As it is, I have to rely on clojure.tools.reader to assign line and column numbers to each read form.

Besides that, I think this feature would enable other useful static analysis and error reporting features.

As far as my use case is concerned, at least, it would be enough if this were an optional feature of `read` that'd be off by default.