10

With the current Rakudo compiler (v2021.10), symbols declared with the ::(…) form do not need to follow the rules for identifiers even when they declare the name of a routine.

This means that the following is code produces the indicated output:

class C { method ::("A method name that's also a sentence!") { say "this works"} }
sub ::("☺") { say "also works" }

C."A method name that's also a sentence!"();  # OUTPUT: «this works»
&::("☺")();                                   # OUTPUT: «also works»

My question is whether this is valid Raku/an intentional feature or whether it's something accidental or Rakudo specific. I don't see any mention of this syntax in the Raku docs, nor do I see a Roast test covers creating symbols like this.

(There is a somewhat related Roast test about using special characters in symbolic dereferences. However, in addition to not being directly on-point, that test contains the slightly unhelpful comment "Note: I'm not 100% sure this is legal syntax". That comment (and that test) were added more than 13 years ago, so this area doesn't seem to have attracted a lot of attention.)

I'm asking in part because, if legal/intended, this syntax seems like one that could be pretty useful in niche situations (especially for methods, where the calling syntax is nicer). It reminds me a bit of Kotlin's syntax `for allowing spaces in backtick delimited method names`. So, if it's part of Raku, I'd like to use this syntax (sparingly!) and add it to the docs.

codesections
  • 8,900
  • 16
  • 50

1 Answers1

12

In short, yes, it's legal.

The concept of an identifier is a syntactic one: when parsing Raku, the parser needs to classify the things it sees, and the identifier rules indicate what sequences of characters should be recognized as an identifier.

By contrast, stashes, method tables, and lexical scopes are ultimately hash-like data structures: they map string keys into stored values. Just as there's no limit on what keys one can put into a hash, there's not one here either. Given meta-objects can be user-defined, it's unclear one could reliably enforce limits, even if it was considered desirable.

The ::(...) indirect name syntax in declarative contexts comes only with the restriction that what you put there must be a compile-time constant. So far as parsing goes, what comes inside of the parentheses is an expression. The compiler wants to get a string that it can use to install a symbol somewhere; with identifiers it comes directly from the program source text, and with indirect name syntax by evaluating the constant that is found there. In either case, it's used to make an entry in a symbol table, and those don't care, and thus between the two, you have a way to get symbol table entries that don't have identifier syntax.

Jonathan Worthington
  • 29,104
  • 2
  • 97
  • 136