I can see that writing a compiler for Nim is difficult. If the source code is perfect, it is (relatively) easy to write a compiler.
However, when the source code is imperfect (newbie talking here), then sometimes the error diagnostic from the compiler is a bit strange.
I encountered the error message "Error: value of type 'proc (){.gcsafe, locks: 0.}' has to be discarded" when compiling the code:
proc needs_parens = echo("This proc needs parens in call") discard needs_parens
This was fixed by just adding a pair of parens at the end of the call statement:
needs_parens()
The compiler needs the parenthesis to "know" that you want to call it. Without them it is just a variable (procvar). I am not sure if it could/should not be changed to be interpreted as calling the proc in this special situation. Maybe there are reasons for this I don't know :)
This error itself is analog to:
let foo = "test"
foo
which says: Error: value of type 'string' has to be discarded
See also:
proc foo(): string =
"hello"
foo()
which says: Error: value of type 'string' has to be discarded
I would expect the error to be something like
Error: you cannot use proc like that. Suggestions:
- needs_parens()
- let myVar = needs_parens
But that would be too informative for nim :D.
Well the error is not that you can't use the proc like that. The error is that you do not use it like that :)
It "could" give a hint that maybe the parenthesis are missing because you meant to call the proc (which is probably the case most of the time when a proc var is discarded).
Yes, if it is possible to give a good error message, then give it.
It is easy to say, but I'm not the guy making the changes in the compiler parser. There must be thousands of similar messages - to be written.
Maybe over time, enough of these hint messages will be written - so the Newbie's can make easier progress - and Nim will grow in popularity.
Actually, I wonder why one would expect that to work in the first place? I don't know any language right know where this would be allowed or is something else than a function pointer. Bit I am sure there are some.. besides Forth :)
Is this because of?
For object oriented programming, the syntax obj.method(args) can be used instead of method(obj, args). The parentheses can be omitted if there are no remaining arguments: obj.len (instead of len(obj)).
In this alternative form there is always one parameter (obj in the case above). The rule here is: If a proc has no arguments you need the parenthesis to indicate that you want to call it.
The error message is just the generic message for discarded values. More information goes IMHO straight into the "linter tools" area. I think if one starts to add those to the compiler you really get hundreds of new "linter warnings".
And besides that... I did that error too at least once. Finding out what was going wrong made me not do it ever again :)
But this is just one special case, and there are lots of others like this. And though it would be good for a user to have different error messages for each such special case (not just one message for each type of errors, but depending on context), seek for error messages comprehensibility can make probably error handling code in compiler half of all the compiler code in size. Other compilers/interpreters/servers/... do the same - just map each error type to one message regardless of context, letting the user to investigate further the cause of the error by his own, with very rare additional hints (like "maybe parentheses missing because ...").
Example. Regarding this error type another special case is when trying to return a value by the last expression from a procedure not having a return value:
proc p =
5
p()
The same error message here, and some user could expect something like "Proc p doesn't have a return value in its signature" instead. But there are most likely other cases, when another message for the same error is expected. And it's scarcely realistic to cover all special cases for error types.
besides Forth
Pascal, Ruby
Those examples may be something for a lint tool. They "guesstimate" what you probably tried to do. The compiler should compile what is offered and his context is "clear" and not something it should guess to much about. At least until it does this 100% correct :)
If you think you could come up with better error message or creating a lint tool, that would be fine! You could try to add something like such "hints" to the errors. That is the beauty of open source!
Even just collecting such examples could help to create such a tool.
@LeuGim I read your comment as that you also don't think the compiler should integrate this. I meant that the example you provide is another case of what a lint tool could catch. Sorry for making it sound as I targeted you specifically.
I am all for such tools but I don't think that the faith of Nim is related to that. Like I said: It should 100% compile correctly first :)
I'm addressing the main issue - meaningful error messages. They can come from the compiler or a lint tool.
In the documentation, http://nim-lang.org/docs/manual.html#statements-and-expressions-table-constructor
There is a section on:
Command invocation syntax
Routines can be invoked without the () if the call is syntatically a statement.
I think I must have read this sentence early on - and misunderstood it.
I definitely think that in terms of error messages rust is what every compiler should aspire to be.
Of course that is kind of necessary since rust has so many unfamiliar concepts and hard to get right syntax.
Nim's error messages generally need a bit of detective work to figure out. Once you have some feel for what goes on behind the scenes that doesn't cost much time but it is a barrier to new users and could be a great QoL improvement for experienced users long term.
One caveat: it is super annoying to figure out bugs in macros and generally I just recompile with echo treeRepr result before even trying to understand if it isn't trivial. A simple way to output or even render the created ast on compile error would be an amazing and maybe not too complex improvement.