To have both names accessible from Scala with @aka
, it could possibly just be a static macro annotation that duplicates the def
signature and calls one from the other. So if such macro annotations will be possible in Scala 3.x, we get it for free.
my 2 bikeshedding cents:
- I really like the idea that itās the alphanumeric name that should be cannonical
-
@symbol("...")
is probably better than@aka("...")
, because it emphasizes that itās for symbolic names of members; seeing āakaā doesnāt immediately suggest āAlso Known Asā ā being lowercase doesnāt help -
@targetName("...")
is probably better than@bytecodeName("...")
, because Scala has other targets besides JVM bytecode, like LLVM bitcode or JavaScript - if we can have more than 1 annotation, it would be better to separate the concern of
symbol
andtargetName
This is how it would look:
trait Monoid[A] {
extension(self: A)
@symbol("++")
def combine(that: A): A
def empty: A
}
def fn(a: Any)
@targetName("fnT")
def fn[T](t: T)
@symbol("*>") @targetName("starRight")
def productR[F[_], A, B](fa: F[A], fb: F[B]): F[B]
On the other hand, I understand the argument that allowing both alphanumeric and symbolic name for the same method is giving ātoo much freedomā to the library author which would cause āmessā for the users of that library.
From that point of view, Scala should force library authors to pick either an alphanumeric or symbolic name for a particular method. While requiring that symbolic name still has an alpha
label for the purposes of documentation and googling. But that alpha name wouldnāt be usable to call the method.
I really appreciated that freedom when /:
was still hanging around, and itās not like thereās a way to prevent the inclusion of both the symbolic and alphanumeric versions.
Itās just a question of how easy that should be to implement, and I would tend to err on the side of making it easier for library maintainers to make it easy for library users. I donāt really see how providing a named alternative to an operator could hurt ease of use.
Is Scala the only JVM language allowing, say, +
as a method name? It would be a pity if there was another language out there that could use +
but doesnāt see it in a Scala class.
Good point. Kotlin allows the standard operators to be āoverloadedā, and a + b
is seen as a.plus(b)
. As I said above, itād be nice if we did the same at least for standard operators.
Your post conveys very well my opinion on the topic.
I agree that alphanumeric names should be the default for any non-standard operator.
I prefer @symbol, or perhaps even @symbolic to make it clear that a secondary symbolic name can be provided, but a second alphanumeric name cannot be provided.
I like the proposal from @sideeffffect to separate the concerns of dual names e.g. @symbol
and encoding at the low level e.g. @targetName
. If there is restrictions on symbolic names then I think āstandardā operators such as + - * should be an exception so that classes like Complex
and Point
and Time
etc can be defined without strange/awkward syntax/annotations/imports.
I agree that it is good to be more āopinionatedā and less āliberal/pragmaticā after learning from Scala 2 to gain increased regularity/consistency in Scala 3, but I think we here need to strive for a balance point in the middle (lagom as we say in Sweden for just right ) and it should not go āextremeā on the either side.
After all it is anyhow possible to create incomprehensible method names using only lettersā¦ Idioms are nice help but contextual and not law.
Duelling dual names could be resolved by using export with rename:
class C { def addAll() = () ; export this.{addAll => ++=} }
seems a shame that export is illegal from this
Whatever brilliant annotation or set of annotations and ingenious semantics result out of this discussion, I hope this statement still stands. Apart from the beginner-argument, letās not forget that (hopefully) by far the most code is application code, not library code. IMHO when writing application code you get virtually no benefit from having to add extra annotations, only useless boilerplate and possibly confusion.
This can be worked around with a proxy object:
class C { outer =>
export proxy.{addAll => ++=}
object proxy {
export outer.addAll
}
}
It ought to really work on this.
though, as I donāt see a reason for it not to. Iāve opened an issue sometime ago to track this: Cannot create renamed copies of members of `this` using `export` Ā· Issue #9704 Ā· lampepfl/dotty Ā· GitHub
The suggestion to add a targetName
parameter to @symbol
annotation was because there would be no way to add such an annotation to the generated operator method since it has no symbol.
It could be useful to annotate both the original symbol AND the generated symbol with their own @targetName
annotations, e.g. to support bytecode-ambiguous set of overloads for both the alphanumeric and the symbolic name.
Though I guess you could expand the symbols into explicit def
s in that case and annotate them, but that could also make you lose some niceties such as an IDE showing the original function instead of the alias ā however, if export
gains an ability to add annotations, these advanced use cases could be implemented using annotated export
ās, for which an IDE could reference the original definitions, instead of exported, too.
Iāve found it is very rare but not vanishingly rare that I write code or read code where symbolic notation helps. I think that @symbol - opt in - would be a better option than @alpha - opt out. And Iād like to be able to import the symbols separate from the rest of the library.
At work we write code for a scala project that is 12 years old. We plan for another 12. The rule weāve adopted is āif the symbol is in a text book that weāve all used then itās OK. Otherwise use words.ā In my own hobby code Iāve found that I rarely use a given library to the extent the authorsā expect. One of Scalaās great strength is the ability to sample from multiple libraries as needed. I would never want to deal with code that relied on two libraries competing for the same symbol, or - possibly worse - similar-looking slightly-different symbols.
The important but rare exception is numerics. Symbols from Spire mostly make sense. Symbols for graphs and processes were confusing. Symbols for general data structures didnāt capture the nuances of words. There are often better options; I no longer use + to chain strings together because s"" seems universally better.
Encouraging library authors to always supply names, and - when it seems wise to them - to supply symbols - seems a better choice that leaves the rest of us the freedom to follow them as far as we choose. Maybe something that builds on the idea of import renaming in a standard way - a standard namespace to import for a libraryās symbols - might serve developersā needs well while letting library authors encourage us to follow their path.
Thanks,
David
Symbols also set associativity and precedence. Itās not something that can be accomplished with pure names.
Thereās now a PR to rename @alpha to @targetName, with the added power that you can use @targetName to avoid conflicting method definitions that have the same erasure.