Warnings
Posted: 03 Sep 2023, 02:05
This post is mostly a development of this post and thread.
First, for easier reference I'll copy my opinion about errors and warnings from that thread:
Currently there is no good way to *warn* about something when, for example, writing a library. It's possible to throw errors, but the default method of displaying them (dialogs) would generally not be suitable for warnings, especially for newer users who might not know how to redirect the errors into another modality. OutputDebug is one way, but it has the limitation of not reporting line number and file automatically, so it would fall to the library creator to always include those; and it can't easily be redirected (eg into a log-file) like is possible with errors (OnError).
Arguably another deterrent to actually using warnings in libraries/scripts is the waryness abot impact on script speed. AHK is known as a slow language already because of it's interpreted, and developers don't want to add extra "fluff" that could reduce script execution speed even further.
Default output
First I want to discuss the way warnings are and perhaps should be outputted to the used. At the moment we have only load-time warnings available via #Warn: VarUnset, Unreachable, and LocalSameAsGlobal. These, if met, by default issue continuable errors as a dialog (MsgBox). For VarUnset and Unreachable this seems fairly reasonable if accounting for beginner users, because these definitely help prevent errors down the line. This is especially true for VarUnset, which usually causes an actual error if not fixed.
However, LocalSameAsGlobal doesn't fit the same pattern: it might or might not prevent errors, but more likely reveals collisions with user-defined libraries, forces library writers to explicitly define all local variables as local to avoid the user getting a warning from common variable name collisions (i, j, out, etc...), and generally has a lower priority of taking action than the other ones. If LocalSameAsGlobal was also enabled by default this would most likely cause more annoyance at the warning pop-ups rather than help write better code. Thus LocalSameAsGlobal default output method should in my opinion be something more "silent" such as StdOut or OutputDebug.
Additionally, at the moment there are no runtime warnings, but if there were then it would probably be that some warnings are more important than others. For example, Python has deprecation warnings, which in AHK could be implemented for example in functions using RegisterShellHookWindow, which is flagged as deprecated by Microsoft. Warnings such as these should not throw dialogs at users either.
Best "silent" output method?
The question is which "silent" output method should be preferred? I argued in the other thread that OutputDebug seems best:
Also, other programming languages tend to output their errors and warnings to a console of some kind, so either one wouldn't be straying far from the norm.
Another option would be logging into a log-file which would be more accessible to beginners (not requiring downloading a special debugger/console). But I would guess that people who are interested in warnings are also savvy enough to use an editor that supports debugging or StdErr outputting, so it wouldn't be my first nor second pick.
Additionally, if silent warnings were the norm then I think that *all* warnings could be enabled by default, including the loadtime warning LocalSameAsGlobal.
Possible syntax for warnings
The output method for runtime warnings could be changed via #Warn Runtime, WarningMode. And the default start settings could be:
Also, runtime warnings should output only once by default: it is not necessary to see for example a deprecation warning every time the function is called.
Warning levels
Other languages often implement warning levels to separate less important warnings from more important ones, but at the moment the usefulness of those seem quite low as runtime warnings are not used yet and the need is not there. But if they were considered, I like how Rust separates types of debug information.
Script execution speed
Regarding the negative impact of the extra code on script execution speeds... I don't really see a way of conditionally "cutting out" the extra code without preprocessor directives. Currently the only way is if the script is planned to be compiled, then ;@Ahk2Exe-IgnoreBegin compiler directive can be used. Because preprocessor directive support has been in the talks for at least 15 years I assumed it's a lot of work to implement and thus suggested a simpler form in the other thread:
but of course it would be preferred to have something like
or to make it more standard, #Warn Runtime could define WARN and then #IfDef WARN could be used instead.
Conclusion
All in all this seems like something that could be improved in AHK, but I'm not exactly sure of the exact way (or if at all? perhaps there is no interest in it). So I'm intrested in any thoughts about preferred output methods, necessity of warnings etc...
First, for easier reference I'll copy my opinion about errors and warnings from that thread:
Current status & issuesConcept-wise, in my opinion errors are serious problems in code from which the code cannot recover from on its own nor can continue without addressing the error. Warnings on the other hand are problems which *are* recoverable, or signal that under certain conditions (which may or may not have been met) the code might fail or cause problems. The current #Warn directives cause "continuable errors", which in my opinion is an oxymoron: it shouldn't be possible to continue after an error, these are in my opinion warnings.
Currently there is no good way to *warn* about something when, for example, writing a library. It's possible to throw errors, but the default method of displaying them (dialogs) would generally not be suitable for warnings, especially for newer users who might not know how to redirect the errors into another modality. OutputDebug is one way, but it has the limitation of not reporting line number and file automatically, so it would fall to the library creator to always include those; and it can't easily be redirected (eg into a log-file) like is possible with errors (OnError).
Arguably another deterrent to actually using warnings in libraries/scripts is the waryness abot impact on script speed. AHK is known as a slow language already because of it's interpreted, and developers don't want to add extra "fluff" that could reduce script execution speed even further.
Default output
First I want to discuss the way warnings are and perhaps should be outputted to the used. At the moment we have only load-time warnings available via #Warn: VarUnset, Unreachable, and LocalSameAsGlobal. These, if met, by default issue continuable errors as a dialog (MsgBox). For VarUnset and Unreachable this seems fairly reasonable if accounting for beginner users, because these definitely help prevent errors down the line. This is especially true for VarUnset, which usually causes an actual error if not fixed.
However, LocalSameAsGlobal doesn't fit the same pattern: it might or might not prevent errors, but more likely reveals collisions with user-defined libraries, forces library writers to explicitly define all local variables as local to avoid the user getting a warning from common variable name collisions (i, j, out, etc...), and generally has a lower priority of taking action than the other ones. If LocalSameAsGlobal was also enabled by default this would most likely cause more annoyance at the warning pop-ups rather than help write better code. Thus LocalSameAsGlobal default output method should in my opinion be something more "silent" such as StdOut or OutputDebug.
Additionally, at the moment there are no runtime warnings, but if there were then it would probably be that some warnings are more important than others. For example, Python has deprecation warnings, which in AHK could be implemented for example in functions using RegisterShellHookWindow, which is flagged as deprecated by Microsoft. Warnings such as these should not throw dialogs at users either.
Best "silent" output method?
The question is which "silent" output method should be preferred? I argued in the other thread that OutputDebug seems best:
But using StdErr might be preferred to keep errors/warnings separate from other debugging outputs?I also expect that users who know to enable warnings are also using software that allows for debugging, so OutputDebug seems like the best choice over StdOut or logging to a file.
Also, other programming languages tend to output their errors and warnings to a console of some kind, so either one wouldn't be straying far from the norm.
Another option would be logging into a log-file which would be more accessible to beginners (not requiring downloading a special debugger/console). But I would guess that people who are interested in warnings are also savvy enough to use an editor that supports debugging or StdErr outputting, so it wouldn't be my first nor second pick.
Additionally, if silent warnings were the norm then I think that *all* warnings could be enabled by default, including the loadtime warning LocalSameAsGlobal.
Possible syntax for warnings
Okay, wouldn't make sense to throw something that isn't catchable. Perhaps a simple Log.Warn("Outputs line and file of where it came from?") is enough? The syntax would lend way to extend Log with other types of information as well.lexikos wrote: ↑01 Sep 2023, 23:38Throw is already continuable in v2.1-alpha.3, which I am preparing for release. As with all continuable errors, it is continuable only if try/catch is not in use.It might be useful to have a way to throw continuable errors as well, for example with throw Warning("This is continuable and creates a stack-trace like a normal error").
Exceptions are thrown. Throwing a warning makes no sense. A warning just warns.
The output method for runtime warnings could be changed via #Warn Runtime, WarningMode. And the default start settings could be:
Code: Select all
#Warn
#Warn LocalSameAsGlobal, OutputDebug/StdErr
#Warn Runtime, OutputDebug/StdErr
Warning levels
Other languages often implement warning levels to separate less important warnings from more important ones, but at the moment the usefulness of those seem quite low as runtime warnings are not used yet and the need is not there. But if they were considered, I like how Rust separates types of debug information.
Script execution speed
Regarding the negative impact of the extra code on script execution speeds... I don't really see a way of conditionally "cutting out" the extra code without preprocessor directives. Currently the only way is if the script is planned to be compiled, then ;@Ahk2Exe-IgnoreBegin compiler directive can be used. Because preprocessor directive support has been in the talks for at least 15 years I assumed it's a lot of work to implement and thus suggested a simpler form in the other thread:
Code: Select all
#IfWarn
Log.Warn("#Warn Runtime is off")
#If
Code: Select all
#define DEBUG
#IfDef DEBUG
Log.Warn("Debugging is enabled")
#EndIf
Conclusion
All in all this seems like something that could be improved in AHK, but I'm not exactly sure of the exact way (or if at all? perhaps there is no interest in it). So I'm intrested in any thoughts about preferred output methods, necessity of warnings etc...