[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)