Would it be possible in Javascript or Python to implement something like "non standard evaluation" in R?

Viewed 360

In R you can write functions that allow arguments to be unquoted attributes of a pre-defined object. For example, the interface to the DataFrame object allows the following:

# df has columns "A" and "B"
df = mutate(df, C=A*B)

Now df has a new column "C" that is the product of columns "A" and "B".

There is also the "formula" type which is unquoted:

lm(data=df, A~B)

This "Non-Standard Evaluation."

Is it fundamentally possible to do something similar in Javascript or Python.

2 Answers

No, it is not possible to have NSE in Python and JavaScript.


Why is that? That is because in Python and JS, arguments are evaluated BEFORE they are passed to the function, while it is not the case in R.


Let's consider the two similar codes in R and Python:

main.R

enthusiastic_print <- function(x) {
   print("Welcome!")
   print(x)
}

enthusiastic_print("a" + 3)

main.py

def enthusiastic_print(x):
   print("Welcome!")
   print(x)
}

enthusiastic_print("a" + 3)

They will both procude an error. But now, let's have a look at when the error occurs:

.R

[1] "Welcome!"
Error in "a" + 3 : non-numeric argument to binary operator
exit status 1

.py

Traceback (most recent call last):
  File "main.py", line 6, in <module>
    enthusiastic_print("a" + 3)
TypeError: can only concatenate str (not "int") to str

You can see that Python evaluates what is passed to the function BEFORE the call. While R, keeps the complete expression passed as argument and evaluates it only when it is necessary.


You can even write this code in R that will produce NO error:

foo <- function(x) {
  print("Welcome in foo!")
  print("I never mess with args...")
}

foo("a" + 3)

You can also capture what was passed as argument and not evaluate it:

verbatim_arg <- function(x) {
  print(substitute(x))
}
  
verbatim_arg("a" + 3)

which produces:

"a" + 3

Finally, that's the functions substitute() combined with eval() which permit to use formulas and all the other NSE stuff.


Supplementary:

You can do the same test in node.js

function enthusiastic_print(x) {
  console.log("Welcome!")
  console.log(x)
}

enthusiastic_print("a".notAMethod())

Well, the sympy library kind of does something similar in python, by letting you define placeholder variables which will only be evaluated later.

Related