vapourlang / vapour

Typed superset of R
http://vapour.run
Apache License 2.0
194 stars 3 forks source link

Issues with syntax & type checking anonymous functions #71

Closed ElianHugh closed 1 month ago

ElianHugh commented 2 months ago

Found with vapour 0.0.5

Maybe an odd-ball case, but it seems like the syntax and type checking for anonymous functions is off? I've found two cases where the checker doesn't throw a warning or error:

# technically wrong type
const anonymous: int = (): int => { 2 }

lapply(1..10, (): int => {
    this is not valid but doesnt throw an error
})

The latter compiles to invalid R code:

lapply(1:10
, function() {
thisisnotvalidbutdoesntthrowanerror})

Note that the requirement of explicit returns are also not checked with the above function

JohnCoene commented 2 months ago

Indeed.

I know we can do this in Javascript but I did not intend on allowing that: const anonymous: int = (): int => { 2 }

I will check but it could be that this fails for the same reason.

lapply(1..10, (): int => {
    this is not valid but doesnt throw an error
})

As for the enforced return it's a bug, I might have forgotten to enforce that on anonymous functions.

Thank you for reporting all these!

JohnCoene commented 2 months ago

I really did not intent on the function below to be valid

const anonymous: int = (): int => { 
  return 2
}

But I added tests and it seems to transpile fine. Unsure what to do.

I believe it was not intended to be used to declare named functions in Javascript either but it does also work and has become quite a popular way of declaring functions.

I myself do it all the time but I understand the criticism that it is relatively unclear to most (e.g.: no func or function keyword found anywhere in function declarations)

Do you have any thoughts on that?

ElianHugh commented 2 months ago

I am definitely guilty of the same in JS/TS, though I am unsure of its role in vapour. In this case, there isn't any variable "hoisting" in R, so that's one less reason for it to be legal syntax. Though, on the other hand, it feels pretty "functional" to allow functions to be treated as variables.

One thing that is nice is that we can ensure that a function is treated as a constant, unlike using the func keyword.

func a_function(): null { return NULL }
const a_function: func = (): null => {}
a_function = mean  # `a_function` is a constant

Edit:

Also, if function expressions are allowed, shouldn't the type of the variable be func and not int? Or even func() int