Is there a way to make the first use of a variable not qualify as “use” of a variable, for example by an annotation?
I find that the warning useful to clean up unused code, but often I run into the problem of the variable essentially being unused, but pretty-printed for debug purposes:
let foo bar baz =
Logs.debug (fun m -> m "bar: %s baz: %s" bar baz);
baz (* bar is unused, but since the debug message "uses" it, I don't get the error *)
I guess I am looking for something like
let foo bar baz =
(Logs.debug [@dont'register'use]) (fun m -> m "bar: %s baz: %s" bar baz);
baz (* bar is unused, but since the debug message "uses" it, I don't get the error *)
or
let foo bar baz =
Logs.debug (fun m -> m "bar: %s baz: %s" (bar [@dont'register'use]) baz);
baz (* bar is unused, but since the debug message "uses" it, I don't get the error *)
You can use a leading underscore to suppress “unused” warnings. This doesn’t satisfy your “first use only” requirement, but it might be enough, or at least better. (And you might already know about this, and it isn’t sufficient.)
let foo _bar baz =
Logs.debug (fun m -> m "bar: %s baz: %s" _bar baz);
baz
Here, if the Logs.debug line is removed, or conditionally compiled out, the warning won’t trigger.
You could also make sure warning 27 is only enabled when debug statements are not filtered out. I think this makes sense, since it is a good idea to have comprehensive warnings and debugging enabled during development, and to disable warnings during opam builds to avoid accidental breakage for new compiler versions and new library versions. (Strictly speaking I don’t think warning 27 needs be be disabled during production builds, since it I think it only depends on the application itself, but other warnings, like deprecations and warnings which depends on the analysis-capabilities of the compiler should be disabled for production builds.)
No, this doesn’t work. The following works and looks a little bit more ridiculous:
let debug_mode = ref true
let debug print =
if !debug_mode then print ()
let foo bar baz =
let bar, baz =
debug (fun () -> Printf.printf "%s %s\n" bar baz);
bar, baz
in
baz
let debug_mode = ref true
let debug print =
if !debug_mode then print ()
let foo bar baz =
debug (fun () -> Printf.printf "%s %s\n" bar baz);
let bar, baz = bar, baz in
baz
@mjambon continuing your idea, I think I like this pattern:
let foo dbg_bar dbg_baz =
let bar, baz = dbg_bar, dbg_baz in
let dbg_catenated = bar ^ baz in let catenated = dbg_catenated in
Logs.debug (fun m -> m "Debug 1: %s %s" dbg_bar dbg_baz);
Logs.debug (fun m -> m "Debug 2: %s" dbg_catenated);
baz
This has the benefit of not having to rebind the variables after each debug statement.
Ah, sorry! I somehow misinterpreted even though you wrote clearly.
As for conditional compilation, that was just an assumption which followed my misinterpretation – I thought you might be presenting the compiler different views, with and without debug lines.
I totally bodged my first post to Discuss. Good start.
@atavener no worries, your idea was good; removing debug code by conditional compilation would still solve my problem! Unfortunately I haven’t really found a nice way to do conditional compilation without hacky solutions that requires spending ages on the build system.
Coming from Java-land, this kind of check reminds me of an IDE inspection, as opposed to something that the compiler would do. Since this is OCaml-land, however, it makes sense to me that the compiler would provide this functionality, similar to how one can turn off warnings like:
let[@warning "-27"] foo a b =
Printf.printf "%d" a;
b + 1
Something like the following makes sense to me maybe? :
let[@variable_usage_counting "off"] debug_print s a =
Printf.printf s a