# Draft for a proposal for a Pure Function API

**URL:** <https://es.discourse.group/t/draft-for-a-proposal-for-a-pure-function-api/1476>\
**Category:** 🦋 Proposals\
**Tags:** proposal\
**Created:** [September 30, 2022, 11:53pm UTC](https://es.discourse.group/t/draft-for-a-proposal-for-a-pure-function-api/1476 "2022-09-30T23:53:32Z")\
**Posts on this page:** 1\
**Showing post:** 12

<div class="post-metadata">

**Author:** ![JOTSR](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jotsr/32/1511_2.png) [@JOTSR](https://es.discourse.group/u/JOTSR)\
**Post date:** [February 1, 2023, 1:10pm UTC](https://es.discourse.group/t/draft-for-a-proposal-for-a-pure-function-api/1476/12 "2023-02-01T13:10:48Z")

</div>

> [@mhofman](#):
>
> There is no notion of owned reference in JS and I don't see how one could be introduced.

It is only for example as I made this proposal compatible with [Explicit Ownership Syntax](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473) and [Explicit Reference Syntax](https://es.discourse.group/t/draft-for-a-proposal-of-an-explicit-reference-syntax/1475). I just said if any future proposal provide a such functionnality it will be valid as arguments.

> [@mhofman](#):
>
> Similarly, JS is a dynamic language and you can't know before execution what the type of a binding is. In particular you can't know if a binding in scope would be a pure function or not, at least not until trying to invoke it.

You can do this check at parse time as it is a syntax rule of this proposal (or at least at runtime), eg:

```javascript
const arrow = () => true

fn pure(arrow = arrow /* ...args */) {
  // code
  console.log(/* code */)
  //code
  arrow()
}

```

Can result in a pseudo AST of shape

```javascript
{
  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.

> [@mhofman](#):
>
> And that's where things start to get really sticky. If the implementation can't throw, how would calling non pure functions or accessing non pure objects be prevented? Also stack overflows etc.

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.

> [@mhofman](#):
>
> I don't see what's simple. I don't consider purity as an optimization vector but as a way for invoking code to make sure what it calls is side effect free.

`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:

```javascript
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

```javascript
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
  }
}

```

> [@mhofman](#):
>
> On the scoping topic, you have to be consistent. Either you have access to bindings in global scope, or you don't. Having access to a subset begs the question of how you decide what the subset is.

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:

```javascript
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](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473) and [Explicit Reference Syntax](https://es.discourse.group/t/draft-for-a-proposal-of-an-explicit-reference-syntax/1475) like syntax can be helpful but with these rules we ensure the "purity" of the function.

> [@mhofman](#):
>
> This whole proposal is very hand wavy. JavaScript is not a statically compiled language like rust, and cannot perform "compile time" checks based on what a binding contains.

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.

---

_[View the full topic](https://es.discourse.group/t/draft-for-a-proposal-for-a-pure-function-api/1476)._
