Open sorawee opened 4 years ago
One idea would be to have a (declare-unused id...) form that explicitly says these variables are supposed to be unused and fail to compile if they do get used. Unused variables are pretty common though with functions so I think it would make sense to have some sort of shorthand there.
Using the underscore is common for this but I think this is riskier in a language like rhombus / racket since it has very flexible naming as part of its culture. The underscore trick is fine in non-fundamental forms like define but are much riskier with forms like lambda and let. One pragmatic solution could be to do something weird and less likely to produce conflicts like _@ or something. In that previous case, lambda is the main problematic form so you could also probably just introduce an alternate lambda form with the underscore shorthand.
What sort of conflicts are you imagining? I don't see the risk in making lambda
, let
, and define
treat _
specially. They would have to anyway if we wanted pervasive pattern matching.
I guess the use of _
in fancy-app
is one possible conflict. Perhaps with the unused variable notation, underscore should be treated specially and can't be used as in fancy app anymore. Otherwise, there must be a way to "escape" it somehow.
That case in particular I've thought about a lot, and I don't think it's a conflict because it only applies when _
is used in certain expression positions and this proposed unused variable syntax would only apply when _
is used in binding positions.
But you can't use it if you don't define it!
One solution could be: _
is special. It's provided by Racket and can't be user-defined. Note that _
is also currently provided by Racket, though users can define it too.
I think _
should be special in that it's provided by Racket and can't be user-defined with the "normal" definition forms. But not so special that it can't be re-defined with more primitive definition forms, like a hypothetical core:define-values
or something. Just that the normal define
form couldn't be used to re-define _
.
Yeah I was just imagining using some sort of #%define
form to actually define _
.
If we go down that route, I see little reason why we it shouldn't be a syntax parameter so that you could rename it if you want to in different languages.
Also, one place where currently has special meaning is with contracts. See [->i](https://docs.racket-lang.org/reference/function-contracts.html?q=-%3Ei#%28form.%28%28lib.racket%2Fcontract%2Fbase..rkt%29.-~3ei%29%29). That's part of the reason why I think we need to be really careful attaching any new meaning to underscore.
The other question I wanted to raise is if it is really Racket's responsibility to be reporting unused variables or if that should be the job of tooling? Maybe languages should be allowed to decide how to do this and whether they want to opt into it.
For example, if you were implementing Java in rhombus, it would be nice to be able to use Java annotations for marking unused variables rather than _ which is not a valid identifier in Java.
Another consideration there is that it should ideally be possible to add in extensible unused variable checking without necessarily performing whole program analysis as a language designer. One of the strengths of Racket as a language platform is that you can quickly move out of whole program analysis and into macros/functions instead.
Being a syntax-parameter isn't necessary to be able to rename it... the current _
binding provided by Racket isn't a syntax parameter, and it can still be renamed just fine.
Also, one place where
_
currently has special meaning is with contracts. See->i
. That's part of the reason why I think we need to be really careful attaching any new meaning to underscore.
I think that has the same meaning as we're discussing here: you have to put a name in some binding position, but you're not going to use it so you don't care what it is.
The other question I wanted to raise is if it is really Racket's responsibility to be reporting unused variables or if that should be the job of tooling? Maybe languages should be allowed to decide how to do this and whether they want to opt into it.
Racket turns extra-linguistic mechanisms into linguistic constructs. It's definitely Racket's responsibility to do this kind of analysis: that's arguably one of the biggest advantages of the macro and #lang
system over more conventional tooling. I think the base #lang rhombus
should do this unused variable analysis, and other #lang
implementations can decide whether or not to reuse that if they wish.
A feature I really wish to see in Rhombus is static warning about unused variables, as these are usually mistakes. DrRacket in a sense has this feature already via the tooltip "no bound occurrences". Racket Mode makes this even more explicit by highlighting these unused variables.
However, there are also legitimate unused variables. It would be annoying to see warnings for these legitimate cases. Several languages solve this problem by adding a special notation to indicate unused variables, usually by using identifier
_
or identifier prefixed with_
. Editors / tools then can recognize these identifiers and don't report them as unused.Note that this is not just a convention. It needs a support from the language. For example, the following code should work:
but currently Racket fails with:
Similarly, the following code should work:
but currently Racket fails with:
There's also a question about how to make the notation customizable. It should be possible to create a new language where this unused variable notation is disabled, for example.