Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggestion: Something similar to python decorators #100

Closed
sebffischer opened this issue Mar 19, 2024 · 3 comments
Closed

Suggestion: Something similar to python decorators #100

sebffischer opened this issue Mar 19, 2024 · 3 comments
Labels
meta-proposal Language proposals type-design Discussion regarding design of enhancements or project at large

Comments

@sebffischer
Copy link
Collaborator

See this issue for some discussion: HenrikBengtsson/Wishlist-for-R#131

@dgkf
Copy link
Owner

dgkf commented Mar 19, 2024

I'm not a fan of decorators for R (I say this as a former python-first person who long ago impulsively wrote a package to implement decorators* 😛) for a couple reasons:

  • Unlike python where functions are defined with the syntax def <name>, R's functions are always anonymous and only assigned to a name by general assignment <name> <- function() { }. This means that the decorator syntax goes from sitting directly before a declaration in python land, to sitting before an assignment in R land:

    @decorator
    def fn():
    @decorator
    fn <- function() { }

    Because R treats functions more ubiquitously as data, a decorator is more natively expressed as a wrapping function,

    fn <- decorator(function() { })
  • Even with this constraint, writing a decorator function today in R is quite achievable and could have the syntax:

    decorator %@%
    x <- function() { }

    or even

    decorator |>
    x <- function() { }

    In either case, the operator just needs to handle the special case where the right-hand-side is assignment and deconstruct the assignment expression to intercept the function, decorate it and reassign it to the symbol on the left. I did this ages ago and almost immediately felt it was a terrible idea.

  • Assuming you don't want to implement all the nasty expression manipulation to tease out assignments, you can also use the classic magrittr pipe!

    library(magrittr)
    `%<%` <- function(rhs, lhs) { `%>%`(lhs, rhs) } 
    
    decorator <- function(fn) {
      function(...) {
        cat("decorated ... \n")
        fn(...)
      }
    }
    
    x <- decorator %<%
    function(who = "World") {
      cat("Hello, ", who, "!\n", sep = "")
    }
    
    x()
    # decorated...
    # Hello, World!
  • The last reason is the least scientific - I just personally think that higher-order functions should not be so mystical. When they're given a special syntax they're put on a pedestal that can make them feel alien, which in my eyes is a real shame. Higher-order functions are one of the most expressive and powerful paradigms of any functional language, and I think that hiding them in special syntax just delays people's exposure to this powerful design concept. At least when we use standard operators, it's clear that there isn't anything "special" happening in the syntax (at least no more special than %in%).


*implementation was internal at my employer and I think it's now lost to time, but I've done something similar in dgkf/typewriter where I flag functions as having a type signature using a decorator syntax.

@dgkf dgkf added type-design Discussion regarding design of enhancements or project at large meta-proposal Language proposals labels Mar 19, 2024
@sebffischer
Copy link
Collaborator Author

Well, what can I say, I am convinced!

When they're given a special syntax they're put on a pedestal that can make them feel alien, which in my eyes is a real shame. Higher-order functions are one of the most expressive and powerful paradigms of any functional language, and I think that hiding them in special syntax just delays people's exposure to this powerful design concept.

Now that you mention it, I remember being surprised to learn that decorators are just higher order functions when learning python.
The only problem that I have with wrapping a function definition in a decorator is that I personally think readability suffers when writing it like below.

f <- decorator(function() {
  ...
})

I quite like your last suggestion with the reverse pipe.
Maybe one could even think about supporting the <| syntax in the language (defined just like your %<% from above).

f <- decorator() <| function() {
  ...
}

@sebffischer
Copy link
Collaborator Author

Also closing this as it is not needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
meta-proposal Language proposals type-design Discussion regarding design of enhancements or project at large
Projects
None yet
Development

No branches or pull requests

2 participants