The @alpha notation

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.

1 Like

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 and targetName

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]
7 Likes

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.

4 Likes

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.

2 Likes

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.

1 Like

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.

1 Like

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 :slight_smile: ) 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.

2 Likes

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.

3 Likes

That has already happened: https://github.com/lampepfl/dotty/pull/10093

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

2 Likes

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 defs 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.

1 Like

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

4 Likes

Symbols also set associativity and precedence. Itā€™s not something that can be accomplished with pure names.

3 Likes

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.

7 Likes