online - ¿Por qué las acumulaciones de stack Clojure son tan largas?
clojure vs scala (2)
Respondiendo a tus puntos numerados,
es idiomático en Clojure interoperar directamente con las bibliotecas de Java, por lo que obtener la pila completa de Java puede ser útil si está invocando objetos de Java de alguna manera inesperada o no compatible.
Suena como una buena idea; A menudo, al menos he deseado una opción configurable que me permita ver solo las partes de stacktraces que se originan en mi propio código, suprimiendo todas las capas de idioma subyacentes.
Normalmente solo lo hago de la manera difícil y analizo detenidamente el stacktrace para obtener la línea en mi programa que vomitó, desconectando las partes de
clojure.*
(Y generalmenteclojure.*
cada cambio de minuto así que tengo una idea bastante buena de qué cambio causó el problema ) Algunas de las herramientas de Emacs y Eclipse que he usado le muestran solo el error real y no toda la pila; En general, considero que esto es más útil.En Clojure / oeste en 2012, @chouser dio una agradable charla [PDF] sobre la anatomía de stacktraces, explicó cómo leerlos e introdujo una herramienta de aspecto prometedor, que aparentemente aún no ha visto la luz del día.
En comparación con, digamos, Python, cuyas stacktraces encuentro bastante amigables para el usuario, creo que las stacktraces son una ventaja en Clojure, especialmente para los principiantes. Esto se debe en parte a la naturaleza "alojada" del lenguaje, aunque espero que haya mejoras que podrían realizarse sin agregar complejidad incidental.
He escrito algunos compiladores / intérpretes de juguetes en el pasado, así que asocio las líneas de referencia de stacktraces en los archivos fuente del compilador con errores de compilación.
Si agrego la siguiente definición de función incorrecta a mi proyecto compojure:
(defn dodgy-map []
{:1 :2 :3})
Lein se niega a comenzar:
$ lein ring server-headless
Exception in thread "main" java.lang.RuntimeException: Map literal must contain an even number of forms, compiling:(one_man_wiki/views.clj:19)
at clojure.lang.Compiler.load(Compiler.java:6958)
at clojure.lang.RT.loadResourceScript(RT.java:359)
at clojure.lang.RT.loadResourceScript(RT.java:350)
at clojure.lang.RT.load(RT.java:429)
at clojure.lang.RT.load(RT.java:400)
at clojure.core$load$fn__4890.invoke(core.clj:5415)
at clojure.core$load.doInvoke(core.clj:5414)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5227)
at clojure.core$load_lib.doInvoke(core.clj:5264)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:603)
at clojure.core$load_libs.doInvoke(core.clj:5298)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:603)
at clojure.core$require.doInvoke(core.clj:5381)
at clojure.lang.RestFn.invoke(RestFn.java:457)
at one_man_wiki.handler$eval1564$loading__4784__auto____1565.invoke(handler.clj:1)
at one_man_wiki.handler$eval1564.invoke(handler.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6511)
at clojure.lang.Compiler.eval(Compiler.java:6501)
at clojure.lang.Compiler.load(Compiler.java:6952)
at clojure.lang.RT.loadResourceScript(RT.java:359)
at clojure.lang.RT.loadResourceScript(RT.java:350)
at clojure.lang.RT.load(RT.java:429)
at clojure.lang.RT.load(RT.java:400)
at clojure.core$load$fn__4890.invoke(core.clj:5415)
at clojure.core$load.doInvoke(core.clj:5414)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5227)
at clojure.core$load_lib.doInvoke(core.clj:5264)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:603)
at clojure.core$load_libs.doInvoke(core.clj:5298)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:603)
at clojure.core$require.doInvoke(core.clj:5381)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at user$eval1.invoke(NO_SOURCE_FILE:1)
at clojure.lang.Compiler.eval(Compiler.java:6511)
at clojure.lang.Compiler.eval(Compiler.java:6500)
at clojure.lang.Compiler.eval(Compiler.java:6477)
at clojure.core$eval.invoke(core.clj:2797)
at clojure.main$eval_opt.invoke(main.clj:297)
at clojure.main$initialize.invoke(main.clj:316)
at clojure.main$null_opt.invoke(main.clj:349)
at clojure.main$main.doInvoke(main.clj:427)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:419)
at clojure.lang.AFn.applyToHelper(AFn.java:163)
at clojure.lang.Var.applyTo(Var.java:532)
at clojure.main.main(main.java:37)
Caused by: java.lang.RuntimeException: Map literal must contain an even number of forms
at clojure.lang.Util.runtimeException(Util.java:170)
at clojure.lang.LispReader$MapReader.invoke(LispReader.java:1071)
at clojure.lang.LispReader.readDelimitedList(LispReader.java:1126)
at clojure.lang.LispReader$ListReader.invoke(LispReader.java:962)
at clojure.lang.LispReader.read(LispReader.java:180)
at clojure.lang.Compiler.load(Compiler.java:6949)
... 51 more
Si hago referencia a una variable que no existe:
(defn no-such-variable []
i-dont-exist)
Obtengo un rastreo igualmente descomunal:
Exception in thread "main" java.lang.RuntimeException: Unable to resolve symbol: i-dont-exist in this context, compiling:(one_man_wiki/views.clj:18)
at clojure.lang.Compiler.analyze(Compiler.java:6281)
at clojure.lang.Compiler.analyze(Compiler.java:6223)
at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5618)
at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5054)
at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3674)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6453)
at clojure.lang.Compiler.analyze(Compiler.java:6262)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6443)
at clojure.lang.Compiler.analyze(Compiler.java:6262)
at clojure.lang.Compiler.access$100(Compiler.java:37)
at clojure.lang.Compiler$DefExpr$Parser.parse(Compiler.java:518)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6455)
at clojure.lang.Compiler.analyze(Compiler.java:6262)
at clojure.lang.Compiler.analyze(Compiler.java:6223)
at clojure.lang.Compiler.eval(Compiler.java:6515)
at clojure.lang.Compiler.load(Compiler.java:6952)
at clojure.lang.RT.loadResourceScript(RT.java:359)
at clojure.lang.RT.loadResourceScript(RT.java:350)
at clojure.lang.RT.load(RT.java:429)
at clojure.lang.RT.load(RT.java:400)
at clojure.core$load$fn__4890.invoke(core.clj:5415)
at clojure.core$load.doInvoke(core.clj:5414)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5227)
at clojure.core$load_lib.doInvoke(core.clj:5264)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:603)
at clojure.core$load_libs.doInvoke(core.clj:5298)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:603)
at clojure.core$require.doInvoke(core.clj:5381)
at clojure.lang.RestFn.invoke(RestFn.java:457)
at one_man_wiki.handler$eval1564$loading__4784__auto____1565.invoke(handler.clj:1)
at one_man_wiki.handler$eval1564.invoke(handler.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6511)
at clojure.lang.Compiler.eval(Compiler.java:6501)
at clojure.lang.Compiler.load(Compiler.java:6952)
at clojure.lang.RT.loadResourceScript(RT.java:359)
at clojure.lang.RT.loadResourceScript(RT.java:350)
at clojure.lang.RT.load(RT.java:429)
at clojure.lang.RT.load(RT.java:400)
at clojure.core$load$fn__4890.invoke(core.clj:5415)
at clojure.core$load.doInvoke(core.clj:5414)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5227)
at clojure.core$load_lib.doInvoke(core.clj:5264)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:603)
at clojure.core$load_libs.doInvoke(core.clj:5298)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:603)
at clojure.core$require.doInvoke(core.clj:5381)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at user$eval1.invoke(NO_SOURCE_FILE:1)
at clojure.lang.Compiler.eval(Compiler.java:6511)
at clojure.lang.Compiler.eval(Compiler.java:6500)
at clojure.lang.Compiler.eval(Compiler.java:6477)
at clojure.core$eval.invoke(core.clj:2797)
at clojure.main$eval_opt.invoke(main.clj:297)
at clojure.main$initialize.invoke(main.clj:316)
at clojure.main$null_opt.invoke(main.clj:349)
at clojure.main$main.doInvoke(main.clj:427)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:419)
at clojure.lang.AFn.applyToHelper(AFn.java:163)
at clojure.lang.Var.applyTo(Var.java:532)
at clojure.main.main(main.java:37)
Caused by: java.lang.RuntimeException: Unable to resolve symbol: i-dont-exist in this context
at clojure.lang.Util.runtimeException(Util.java:170)
at clojure.lang.Compiler.resolveIn(Compiler.java:6766)
at clojure.lang.Compiler.resolve(Compiler.java:6710)
at clojure.lang.Compiler.analyzeSymbol(Compiler.java:6671)
at clojure.lang.Compiler.analyze(Compiler.java:6244)
... 66 more
¿Por qué el compilador Clojure no ClojureSyntaxError
un ClojureSyntaxError
y un ClojureNameError
que se pueden capturar en el nivel superior y se muestra un error simple? Estos son errores comunes del desarrollador durante el desarrollo.
Si los trazados largos son útiles en algunas circunstancias, ¿por qué se truncan?
Editar : Lo que estoy buscando en una respuesta:
- ¿Hay situaciones (quizás metaprogramación con interoperabilidad de Java?) Cuando obtener una referencia de rastreo clojure.lang es útil?
- (Relacionado) ¿Existen restricciones técnicas que impidan agregar un
ClojureSyntaxError
como describí anteriormente? ¿Merece la pena abrir un problema en el rastreador de errores Clojure? (actualización: he abierto CLJ-1155 ) - ¿Cómo los programadores de Clojure de la experiencia leen estos tracebacks? ¿Hay herramientas para ayudar? ¿Todos usan clj-stacktrace?
Las stack stack de Clojure son ruidosas, y esa es una queja que aparentemente se escuchó. Algunos librairies proporcionan stacktraces más agradables, como clj-stacktrace o la biblioteca de expectativas .
Pero esto es algo que también se está mejorando en Clojure, por ejemplo con el reciente lanzamiento 1.7 . Ver también clojure.stacktrace api .
Así que apuesto a que solo mejorará con el tiempo. Las cosas son muy emocionantes en el ecosistema Clojure {Script} en este momento.