5.1 Representing Static Information
Static information for an expression or binding is represented in key–value form. When static information is associated with a binding, it is propagated to each use of the bound variable, so we can refer to an expression E that has static information without loss of generality.
Rhombus uses several built-in static-information keys:
statinfo_meta.dot_provider_key —
names a compile-time function that macro-expands any use of . after E. For example, assuming a class Posn(x, y) declaration, p :: Posn associates statinfo_meta.dot_provider_key with uses of p to expand p.x and p.y to field accesses. An expression is a dot provider when it has static information mapped by statinfo_meta.dot_provider_key. statinfo_meta.call_result_key —
provides static information to be attached to a function-call expression where the function position is E. (The arguments in the call do not matter.) For example, class Posn(x, y) associates statinfo_meta.call_result_key with Posn itself, and the associated value is static information with statinfo_meta.dot_provider_key. So, Posn(1, 2) gets statinfo_meta.dot_provider_key that makes Posn(1, 2).x select the 1. statinfo_meta.index_result_key —
provides static information to be attached to a […] indexing reference where E is to the left of the […]. (The index expression inside […] does not matter.) For example ps :: List.of(Posn) associates statinfo_meta.index_result_key to ps, where the associated value includes is static information with statinfo_meta.dot_provider_key. So, ps[i].x is allowed and selects an x field from the Posn instance produced by ps[i]. statinfo_meta.index_get_key and statinfo_meta.index_set_key —
names a form to use for a […] indexing reference or assignment where E is to the left of the […]. (The index expression inside […] does not matter.) For example, p :: Array associates statinfo_meta.index_get_key to p so that p[i] uses an array-specific referencing operation, and it associates statinfo_meta.index_set_key to p so that p[i] = n uses an array-specific assignment operation. statinfo_meta.append_key —
names a form to specialize the ++ operator for appending maps, lists, and similar values. For example, p :: Array associates statinfo_meta.append_key to p so that p ++ q uses an array-specific appending operation.
Static information is associated to a binding through a binding operator/macro, and it can be associated to an expression through a binding or through an expression operator/macro that adds static information to its parsed form (i.e., expansion). For example, the :: operator associates static information through an annotation. An annotation pairs a predicate with a set of static information to associate with any variable that is bound with the annotation. That’s why a binding p :: Posn makes every reference to p a dot provider: the annotation Posn indicates that every binding with the annotation gets a dot provider to access x and y. When :: is used in an expression, then static information indicated by the annotation is similarly associated with the overall :: expression, which is why e :: Posn is a dot provider for any expression e. Function-call forms and map-reference forms similarly attach static information to their parsed forms, sometimes, based on static information attached to the first subexpression.
Note that static information is associated with an expression, not a value. So, if Posn is passed as an argument to a function (instead of being called directly as a constructor), then the function ultimately receives a value and knows nothing of the expression that generated the value. That is, no part of the function’s implementation can take advantage of the fact that directly calling Posn would have formed a dot provider. The function might have an annotation on its argument that indicates a dot-provider constructor, but that’s a feature of the formal argument, and not of an actual value.