[HN Gopher] Compiler Errors for Humans (2015)
___________________________________________________________________
Compiler Errors for Humans (2015)
Author : todsacerdoti
Score : 67 points
Date : 2022-11-24 14:29 UTC (8 hours ago)
(HTM) web link (elm-lang.org)
(TXT) w3m dump (elm-lang.org)
| shadowofneptune wrote:
| I'm reminded of these error messages from an Apple C compiler:
|
| https://www.cs.cmu.edu/~jasonh/personal/humor/compile.html
|
| - "String literal too long (I let you have 512 characters, that's
| 3 more than ANSI said I should)"
|
| - "...And the lord said, 'lo, there shall only be case or default
| labels inside a switch statement'"
|
| - "You can't modify a constant, float upstream, win an argument
| with the IRS, or satisfy this compiler"
|
| Some of them are more helpful than others, but they are all
| rather human.
| mannyv wrote:
| Too many errors on one line, make fewer.
| LoganDark wrote:
| I don't regret reading this comment _before_ clicking the
| link
| mannyv wrote:
| There was one that went something like "a typedef (or
| something) at this point was a complete surprise to me.'
| capableweb wrote:
| Better than the infamous PHP error message made in Hebrew:
| T_PAAMAYIM_NEKUDOTAYIM
| kibwen wrote:
| Elm's error messages were the explicit inspiration for Rust's
| current error messages: https://blog.rust-
| lang.org/2016/08/10/Shape-of-errors-to-com...
| convolvatron wrote:
| everyone opines about lovely rust error messages are. but in
| there is 'you really need to add lifetime annotations'. advice,
| which is followed, will result in days of mad refactoring, only
| to discover that was a _really bad plan_.
|
| pure evil
| dmitriid wrote:
| I think they were an inspiration for most modern languages.
| Either directly or indirectly.
| AlbertCory wrote:
| Favorite experience with compiler errors: C++ in 2004 or so, when
| the errors were so voluminous and inscrutable that you had to
| install another program to massage them into something readable.
| cratermoon wrote:
| The first time I tried writing a C++ program with templates
| (very early on, like mid-late 90s), the compiler error messages
| were longer than the little program I was trying to write. It
| put me off on the language and the compiler so much that I went
| back to plain C and off into Perl and other languages, and
| never really got back to it.
| BoppreH wrote:
| Should a compiler also suggest applying the fix?
|
| I'm working on my own toy language and wondering if simple,
| obvious errors (like the `map` -> `nap` typo from the article)
| should come with an "Apply fix? [y/N]" option when run
| interactively.
| jamesmunns wrote:
| Both Rust (via 'cargo fix') and Clang (via `clang-tidy -fix`
| have ways of doing this, I don't think I've seen someone offer
| this automatically/interactively though.
|
| I don't think I've ever used them, but I've ABSOLUTELY used
| suggested fixes from LSP/rust-analyzer tools, which fit much
| more into my typical workflow. For things like match statements
| in Rust (which need to be exhaustive), I now have muscle memory
| to just write an empty match statement, and trigger the first
| LSP/r-a suggestion, which fills the match block with
| placeholder items.
|
| I guess I see LSP as my "compiler in interactive mode"
| interface (even if that isn't EXACTLY true).
| masklinn wrote:
| Maybe as an opt-in (mode or blanket approval), having to
| continue on every compiler error which has a fixer would be
| rather frustrating.
|
| Clippy supports fixes, but will only apply them if `--fix` is
| supplied. It does not ask for individual case, the assumptions
| likely being that if you're running this opt-in you can
| probably do so with a clean working copy and revert whichever
| fixes you didn't want or are incorrect.
|
| An other issue is if you're providing fixers for suggestions,
| the fixer has to be extremely reliable, not a 90% thing,
| because replacing broken code by possibly subtler broken code
| is not great.
| warpech wrote:
| I collect examples of systems that have helpful error messages.
| Here's a blog post (not mine) that praises error messages in
| React [1]. Any other examples?
|
| [1] https://codeburst.io/the-true-delight-of-reacts-error-and-
| wa...
| seanwilson wrote:
| > Folks who prefer dynamically-typed languages are generally of
| the opinion that working with compiler error messages sucks.
|
| I think a big factor here is dynamic languages can show concrete
| variable instantiations to help you understand what went wrong so
| it's less abstract e.g. the code `plus x y` might give the
| runtime error "x was 'abc' which is type String and not type
| Number" vs something more abstract and confusing like "x is type
| String and not type Number" that you tend to see in compile-time
| errors.
|
| Are there any languages that give concrete variable instantiation
| examples as part of compile-time error messages? For instance,
| example values could be generated from the types, come from
| previous program runs, or supplied by the coder somewhere.
|
| When errors get tricky, you tend to start plugging in concrete
| values or stepping through the program manually so compilers
| could definitely help more here.
| ygaitonde wrote:
| In OCaml, if your pattern match is non-exhaustive, then the
| compiler generates example patterns that you aren't accounting
| for in addition to showing the missing type.
|
| Here's an example:
| https://stackoverflow.com/questions/22737031/this-pattern-ma...
| renox wrote:
| I still wonder why editors don't understand line numbers on the
| CLI <editor> file:5
|
| The editor should try to find if 'file:5' exist and open it if
| so, if it doesn't it should try to open 'foo' and then go to line
| 5.
|
| Sounds sensible no? But I don't know any editor which does this.
| masklinn wrote:
| > The editor should try to find if 'file:5' exist and open it
| if so, if it doesn't it should try to open 'foo' and then go to
| line 5.
|
| Opening a file is often done in creation, and `file:5` is a
| perfectly valid filename, so it's a bit debatable for a
| default.
|
| OTOH in Emacs you should be able to define a find-file-not-
| found-functions hook[0] and implement whatever fallback you
| want. I assume `emacs <file>` calls `find-file` after it's
| initialised the editor itself.
|
| [0]
| https://www.gnu.org/software/emacs/manual/html_node/elisp/Vi...
| renox wrote:
| > Opening a file is often done in creation, and `file:5` is a
| perfectly valid filename, so it's a bit debatable for a
| default
|
| You're right, but even as an option I think it'd be nice.
| euiq wrote:
| Visual Studio Code does this (see "File links"):
| <https://code.visualstudio.com/docs/terminal/basics#_links>
| renox wrote:
| I don't think it works from the CLI: code <file>:5 doesn't do
| what's expected.
| matsemann wrote:
| JetBrains products do this for lots of stuff if you use the
| built in terminal to launch stuff or their runner.
| oftenwrong wrote:
| vim does: vim file +5
| renox wrote:
| But compiler error messages are file:5 so this isn't good
| enough.
| Existenceblinks wrote:
| I seem to have an unpopular opinion about humanized compiler
| error messages. It's better than cryptic messages for sure but I
| think it's worse than robotic but concisely clear error messages.
| For example, for a type error, don't write mini book for me, just
| tell me "line: 56 column: 97, s/int/string/". Same for
| complicated error, don't try to be human it's even more
| confusing.
| cloogshicer wrote:
| Out of genuine curiosity: Why do you think that? Trying to
| understand where you're coming from.
| Existenceblinks wrote:
| I wrote Elm before and while the error message is nice it
| takes longer to iterate and fix stuff. Because It's in a mix
| mode of docs and error message. I only want a clear error
| message concisely.
| cloogshicer wrote:
| Interesting, thanks for explaining.
| jdkoeck wrote:
| > line: 56 column: 97, s/int/string/
|
| Sorry, but that's the least accessible error message I have
| ever read.
| capableweb wrote:
| You haven't dealt with PHP by any chance, have you?
|
| Not saying the above is good/bad, just saying that there are
| (was) worse offenders out there for sure.
| Existenceblinks wrote:
| Half serious, I think JS' "undefined is not a function"
| wouldn't be terrible if it tells me _where_ it lost its
| value. The message itself is already ok.
| Existenceblinks wrote:
| I suspect the downvoter misinterprets my "example".
| s/int/string/ meant to be semantics. Something like diff in
| test or text diff with semantic help.
| dang wrote:
| Discussed at the time:
|
| _Compiler Errors for Humans_ -
| https://news.ycombinator.com/item?id=9805978 - June 2015 (90
| comments)
| dtgriscom wrote:
| In the early '80s at MIT, we learned the CLU [0] language. The
| wonderful aspect of that compiler is that when it hit a syntax
| error it would suspend compilation for a few dozen lines, or
| whatever it took to get past the blast radius of the error, and
| then continue compiling, looking for further errors. You'd see
| the error message on the faulty line, and then a "... resuming
| compilation here" message showing where it would start checking
| for more error messages.
|
| You (obviously) wouldn't get a useable binary, but at least you'd
| see more than one error at a time, without the cascading sequence
| of errors you see in (most?) current compilers.
|
| [0]: https://en.wikipedia.org/wiki/CLU_(programming_language)
| squaredot wrote:
| I would love to have something like this. With Julia, a
| programming language that I like very much, it's really a pain.
| blindseer wrote:
| The first thing I thought when reading this blogpost was "Can I
| send this to a Julia core dev? Would they understand how much
| nicer error messages are in other ecosystems?"
|
| I think even basic things like the order of error messages is
| all backwards to me. Take this very silly example:
| julia> foo() = println(123 * "hello") foo (generic
| function with 1 method) julia> bar() = foo()
| bar (generic function with 1 method) julia> baz()
| = bar() baz (generic function with 1 method)
| julia> baz() ERROR: MethodError: no method matching
| *(::Int64, ::String) Closest candidates are:
| *(::Any, ::Any, ::Any, ::Any...) at operators.jl:591
| *(::T, ::T) where T<:Union{Int128, Int16, Int32, Int64, Int8,
| UInt128, UInt16, UInt32, UInt64, UInt8} at int.jl:88
| *(::Union{AbstractChar, AbstractString}, ::Union{AbstractChar,
| AbstractString}...) at strings/basic.jl:260 ...
| Stacktrace: [1] foo() @ Main ./REPL[3]:1
| [2] bar() @ Main ./REPL[4]:1 [3] baz()
| @ Main ./REPL[5]:1 [4] top-level scope @
| REPL[6]:1
|
| In Julia the type of the error is printed out immediately at
| the point where the error occurs, then a bunch of hints about
| closest candidates, then the function and filename where the
| error occurred, then the function that called it, then the
| function that called that. It's all backwards. In order, it's
|
| 1. important information 2. arbitrary hint which could be
| useless 3. most important (where the error occurred) 4. less
| important 5. less less important
|
| When the stacktrace is long, this is so painful to deal with in
| a REPL environment. You almost always have to scroll to find
| out information about the error, and you have to scroll just
| the right amount, or else ...
|
| And even the stacktrace arguably doesn't contain all the
| information it should, demonstrated well by this blog post how
| nice it could be.
|
| VSCode is preferred way of using Julia (for me and for better
| or for worse for everyone). For long stacktraces I have to
| first scroll all the way back up to see what is going on. So
| often I have a very tiny terminal open at the bottom of my
| screen, and it is EXTREMELY annoying to do that. I often scroll
| too much and I overshoot, and just finding the error is a
| challenge. There's so many times where I'm just struggling to
| find the error, and it's just an exercise in frustration to be
| honest.
|
| Here's the same example in Python. In [1]:
| def foo(): ...: print("1" + 1) ...:
| In [2]: def bar(): ...: foo() ...:
| In [3]: def baz(): ...: bar() ...:
| In [4]: baz() -----------------------------------------
| ---------------------------------- TypeError
| Traceback (most recent call last) Input In [4], in
| <cell line: 1>() ----> 1 baz() Input In
| [3], in baz() 1 def baz(): ----> 2
| bar() Input In [2], in bar() 1 def
| bar(): ----> 2 foo() Input In [1], in
| foo() 1 def foo(): ----> 2 print("1"
| + 1) TypeError: can only concatenate str (not
| "int") to str
|
| The last line tells me the error. The line before that tells me
| where. I can scroll up to find more information if I want to.
|
| Why doesn't Julia work like this? Who knows. I've made
| suggestions on slack and to people in person but I've been met
| with disdain for the most part.
|
| Not to mention that almost ALL my errors are MethodError types.
|
| And worst of all, Julia doesn't show you the string of your
| code in the error, so you have to click on the line that has
| the file and hope VSCode opens that file at that line. It's SO
| backwards. If you are using neovim / vim / tmux, you have
| manually copy paste the line that contains the file name and
| line number into a new terminal. Or just navigate to the file
| and line number manually. Ugh. In Python, I can see the error
| and know what caused the error. In Julia, I see the error, kind
| of sort of know what might be the problem, try to find the
| exact file and line, check if my assumptions are correct, if
| not traverse up the method dispatch call stack and try to
| predict what might be going on.
|
| And I consider myself an experienced Julia developer. For my
| team members coming from Rust or Python when they get a error
| running code, it's just brutal during the learning process.
| I've had people come up to me and say to my face, Julia sucks
| and I shouldn't write or advocate it anymore.
|
| This is barely touching the surface. Error reporting with
| macros is even worse. My team has managed to segfault our
| program multiple times and we are left completely in the dust
| then.
|
| There's SOOOOO many examples like this where I think usability
| in Julia needs to be improved. Sigh. Maybe some day.
| eckza wrote:
| After shipping several production applications in Elm over the
| last five years... I can confirm that the development experience
| is an absolute joy.
|
| With a compiler this helpful, and sub-second builds-on-save - you
| get really tight feedback loops.
|
| I can't say enough good of it.
| capableweb wrote:
| If you enjoy tight feedback loops and want something even
| quicker than "rebuild on save", you should try something like
| Clojure and hook up your editor to a REPL running in the
| background. Rather than "recompile the whole program on save",
| you can send small snippets to be evaluated in the live
| environment, updating your program on the fly :)
| tmtvl wrote:
| I was fairly happy doing REPL development with Scheme, and
| then I decided to give Common Lisp a try and I discovered
| what REAL REPL-driven development is.
|
| The first time I changed some data representation from a
| defclass to a defstruct and SBCL asked me what I wanted to do
| with existing instances of the type was mindblowing.
| hsuduebc2 wrote:
| I sometimes remember horrors of "undefined index of null" which
| are for new developers quite frustrating. Good job!
___________________________________________________________________
(page generated 2022-11-24 23:00 UTC)