Metaprogramming bounds syntax
- Dominant language
- Rust
- Stars
- 145
- Forks
- 5
- PR merge metrics
- No merged PRs in 30d
Description
One thing that has been a central theme of Jan Vitek's work is that R's meta-programming facilities come at a pretty steep performance cost, even though they are used in a small subset of functions. Even though performance isn't a goal, I think the future of an R-alike language should probably consider these ideas and I'm interested in mocking them up.
### Argument Passing
R's defaults are quite nice. Arguments are passed as promises that aren't actually evaluated until they're needed. Even before they're evaluated, their expressions can be rearranged and evaluated in different contexts. This is the central feature of R's meta-programming, but it means that _most_ functions carry forward the machinery for meta-programming even if it would have little impact had the arguments all been eagerly evaluated.
For this purpose, I'm considering a default of _eager_ evaluation, with a syntax for _lazy_ evaluation. The exact syntax is very much up for debate, but the crux is that individual arguments can be flagged as _lazy_:
> #### Example using `.` "context" syntax
>
> ```r
> not_null_else <- function(a, .b) {
> # a eagerly evaluated in parent frame
> if (!is.null(a)) a
> else b # b not evaluated until here as it is just a promise
> }
>
> not_null_else(
> loot_chest(1, 2, 3, 4, 5),
> stop("that password was incorrect")
> )
> ```
>
> Here the `.` syntax is borrowed from [this proposal](https://github.com/dgkf/R/issues/57#issuecomment-1745895529) which uses the `.` to mean something like "in this context". Although not a direct mapping of the concept, it evokes a sense of contextual ambiguity at the interface of the calling frame and evaluation frame.
This would also put nice bounds on [when tail calls are permitted](https://github.com/dgkf/R/issues/60). When a recursive function requires lazily evaluated arguments a standard evaluation model can be used, while functions that take all eager arguments can leverage tail call optimizations.
### Declaring a `static` function
> [!NOTE]
> **Feedback needed:** What is the right name for this behavior?
A `static` function could be an even more restrictive constraint on a function which states that a function
1. only uses parameters and variables defined in its current scope
1. does not evaluate any expressions in other environments (including promises in other environments)
1. only calls out to other static functions
This would allow for much more intensive and useful static code analysis and optimization. I'm a long ways off from even considering such ambitions, but I'd like to get the conversation started on whether it would be worth the cognitive overhead. This is intended to address the [closing thought of Jan Vitek's _R melts brains_](https://youtu.be/VdD0nHbcyk4?t=3300).
> #### Example using `static` keyword
>
> ```r
> f <- static function(n, if_even, if_odd) {
> if (n > 0) f(n - 2, if_even, if_odd)
> else if (n == 0) if_even
> else if_odd
> }
> ```
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.