It is only for example as I made this proposal compatible with Explicit Ownership Syntax and Explicit Reference Syntax. I just said if any future proposal provide a such functionnality it will be valid as arguments.
You can do this check at parse time as it is a syntax rule of this proposal (or at least at runtime), eg:
const arrow = () => true
fn pure(arrow = arrow /* ...args */) {
// code
console.log(/* code */)
//code
arrow()
}
Can result in a pseudo AST of shape
{
type: PureFunction,
name: "pure",
args: [/* */],
body: {
//...
type: Function, //Syntax error (Function are not allowed in PureFunction body)
name: "console.log",
//...
type: ArrowFunction, //also throws
name: "arrow"
//...
}
Of course these checks can be done at runtime for those that can be deduced at parse time.
When I say can't throw, this is not to have fn
that don't throws but you can't use throw new Error()
"manually" or using throwable function. It is a sort of like in rust with Result enum that function can return and panic that is raise by the "runtime" to ensure that the function respect the signature.
fn name() {}
declaration if a constant declaration unlike with function
keyword. As the input and output are "constant" (known before runtime) you could simply unwrape recursive function like:
(only if the function is returning itself)
Only for example, not a guideline of an implementation:
fn recurse(a, b) {
//...
a += 0.1
b = a + b
if (a < 100) return recurse(b, a + 2 * b)
if (a < 200) return b
return a
}
To a tail call optimised form
fn recurse(a, b) {
while (true) { // all the body of the function is passed in the loop
//...
a += 0.1
b = a + b
if (a < 100) {
[a, b] = [b, a + 2 * b] //recursive call is simply transformed into reassignment
continue // + continue
}
if (a < 200) return b
return a
}
}
You only have access to globalThis
not the global scope in order to have access to standard objects like Date, Map, ... . To use a outer scope object you have to pass it explicitely as argument. For the same reason you can't pass a reference as argument as it can be accessed from the outiside.
supposing the following calls:
const c = new Date()
const d = 5
pure(1, [/* primitives or literals*/], c, d, { key: 'prop', date: new Date() }) //error
//c raise a syntax error since it is an external reference, you have to clone it
pure2(date = new Date(c)) //ok date is cloned
An Explicit Ownership Syntax and Explicit Reference Syntax like syntax can be helpful but with these rules we ensure the "purity" of the function.
I think the idea is pretty robust. There is no need to have type since you can distinguish primitives and Object, const
and let
. I also forgot to mention it in my previous posts but with the fn
keyword you declare implicitely a const pure function and like arrow function there is no access to internal properties like arguments
... I think the best is also to don't bind this.