The $ character is reserved for compiler-synthesized identifiers. User programs should not define identifiers which contain $ characters.
Unfortunately, the use of such identifier in user code can lead to compiler crashes, runtime crashes, strange compilation error, or at worst an unexpected change in behavior.
Only a handful of users know about this restriction. Many libraries have used it in the past without knowing the dangers it poses.
This Pre-SIP proposes a definite solution to this problem.
Motivation
Ensure that users do not defined identifiers with undefined behavior without their knowledge.
Remove add-hoc (incomplete) patches from the compiler.
Proposed solution
Disallow user-defined identifiers containing $ and give an escape hatch for the few cases where they are needed.
High-level overview
Given that libraries have accidentally used identifiers with $ we need to have a migration path. We should first emit a migration warning when such an identifier is defined. Then in some following version we can disallow them by emitting an error.
At the same time we need to introduce a way to disable there warnings/errors. As there are few cases where we can define them soundly (i.e. in the Scala 2 standard library), we should make this a -Y compiler flag (-YallowRestrictedCompilerIdentifiers).
Specification
When parsing the name of a definition, the parser should check the identifiers for $ and emit the warning/error unless -YallowRestrictedCompilerIdentifiers is enabled.
Compatibility
This will only affect source compatibility for projects that misused identifiers with $. It will not affect binary compatibility.
Alternatives
In dotty/issues/#18234/comment it was proposed to add this as a linting option (also see dotty/pull/#18563). This would provide the necessary warning, but it does not address the source of the problem. Users that don’t know about this restriction will also not know about the linting option, this will only help experienced users that already know the problem.
A small and incomplete list of issues that this has causes. It is quite difficult to search for these issue in GitHub or Google due the the $ character.
The Scala rules about $ are exactly the same as the Java rules. And as far as I know, it’s not a problem in Java. So why should we be more paranoid than the Java developers?
Java developers don’t use symbols in their identifiers as a rule; in Scala we do this with other symbols, and $ does not seem fundamentally different than +
We have a lot more sources of compiler-generated $s in Scala than in Java; in Java there is basically only inner classes; in Scala we have symbols, module classes, anonymous identifiers (such as params), perhaps others.
Without being hindered by any knowledge of the compile internals, would it not be possible to replace the use of $ by the compiler for some other symbol way up in the unicode table, or a non printable one like 0x11, or even a much less used one like 0xB6?
They would have to use the escape hatch. We will continue doing our best effort to make this work properly. As far as I know, the compiler does not generate methods with a single $; therefore, we should not have any conflicts now. We would need to keep ensuring that we the compiler do not add such a definition.
It is a bit more problematic with class $, class $$, and object $ where we have ambiguities when classloading.
I am in principle against driving the behavior of what the compiler accepts by a -Y flag. We are just now leading parallel discussions about whether we can get rid of those flags.
I maintain my belief that this does not need fixing and any fix would likely make things worse. We have a lot of more urgent things to do than fiddle with this.
Maybe the best approach would be to generate a warning (which can suppressed with wconf).
Would do the job of notifying the user that this is a bad thing to do, and enables the user to acknowledge and move on.
The proposal is to warn or error about use of names with dollars in user definitions, but permit it when the name is in backquotes, as is the convention for other disallowed names.
case class StaticBinding(v: String) {
private def copy$default$1(): String = ???
}
In current List :
@publicInBinary
private[::] def next$access$1 = next
The issue about undetected conflicting members was due to Scala 3’s structured names, where the derived name copy$default$1 is distinct from the simple name that reads the same. This is not unlike JVM dotted names, which are the native or true representation, whereas we always think of them structurally, as a dotted prefix and a simple name. The suggestion, then, is that dollars in names cannot be used naively.
As in the previous effort to “lint” these identifiers, the diagnostic is only at the definition and not at the use site.
The motivation for something stronger than an opt-in warning is that it’s too easy to exploit the syntax unwittingly. Users may be unaware that they should turn on all the available safety equipment. On the other hand, backquotes have become more familiar syntax. Using them for an occasional definition is not burdensome or obscure.
The only place I care about it (and at this point only very slightly – it’s mostly obsolete in practice) is the jquery-facade, which intentionally mimics the corresponding Javascript syntax, so $, on its own, is the most important identifier – it’s the standard alias for jQuery, so it’s really central.
But so long as the warning only needs to be ameliorated at the definition site, not the calls, I believe that’s a non-issue.
$ on its own i believe does not conflict with any generated names?
The fastparse example is probably less established than jquery of course, it just happened to be chosen as the new convention when [_: P] was banned (as _ is now reserved for type lambda)