Nomenclature is important to a JVM MOP since the main programmable channel in invokedynamic
is a name string. Based on the mangling convention described earlier, we will used colon delimiters to structure names into simple token sequences, and use those structured names to manage linkage across the JVM and across languages.
Here are some key questions in designing such names.
1. Should the names be reasonably pleasant to read (modulo mangling effects, which can be hidden in polite company)? Default answer: yes. The dynamic Java design sketch in this wiki uses simple keywords, and they seem to read well.
2. How does a language (or other MOP player) reserve a part of the namespace? Is it enough to say that certain early adopters get short-hand prefixes like ruby:
, python:
, etc? Probably. Eventually we'll need something like fully qualified names, like :com.acme:acmeslang:
3. Does the notation allow elision? For example, if every MOP-name in a compilation unit belongs to AcmeSlang, maybe we can declare that acmeslang:
is optional. But, there should be (a) a way to escape to other name spaces, and (b) no need for an escape to access standard prefixes like method:
. Another way of phrasing this is, can you say the equivalent of import acmeslang:*
, issue names like event:foo
to mean AcmeSlang events, and then issue fully qualified ZeugmaChat names like :com.zeugma:event:bar
. I thinks this kind of importing or context sensitivity is important, that conciseness of bytecodes is a medium-important goal.
3. What are the common notions that can be permanently imported? Anything that the JVM defines natively needs a name. This includes method:
and field:
and element:
and perhaps class:
(if a class or interface can be an operation--and if class:x
then also just int
, boolean
). Certainly new:
. Maybe array element getters and setters Maybe also set:field:
.
4. Also there are well-accepted notions which might as well be common across languages. Those native to the JVM all have natural generalizations to this level (e.g., element applied to a list or other collection, new applied to factory or mixin APIs). There are as:
(conversion) and operator:
(symbols which appear as non-name operations), and perhaps even if:
and for:
, although these probably fall down into language specifics. We need a notion of events for reactive or event-driven programming in the relevant languages.
5. The notion of imperative side effects factors tantalizingly across most operators (field, element, method call). This probably means we need a nomenclature syntax for inverting a getter name into a setter name, regularly. Hence the set:
prefix, as in set:field:f
, set:method:f
.
6. Similarly, there are other modifiers that factor across some of the other constructs: Null handling notations foo?.bar, multiple-value notations foo*.bar or foo(*bar), complex get/set patterns foo*bar = baz or foo() += bar. How are these extra conditions mixed into the basic selection of field/element/method? Are these extra notations mixed in as prefixes (}}nullable:method:foo}}) or suffixes method:foo:nullable
? Probably prefix-only, to avoid ambiguity. Or is there a way to mix several syntactic aspects
together on an equal footing? (Yikes!)
7. How do we leave open spaces for reified generics, if the JVM gets them, or if a language chooses to simulate them? This is another (complex) case of name modification. Keeping the prefix convention, but adding bracket tokens, maybe we have of{:int:}:class:list
.
8. What other degrees of freedom are needed for structured names?