# Draft of a proposal for an Explicit Ownership Syntax

**URL:** <https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473>\
**Category:** 🦋 Proposals\
**Tags:** proposal\
**Created:** [September 30, 2022, 11:47pm UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473 "2022-09-30T23:47:21Z")\
**Posts on this page:** 20\
**Page:** 1

<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:** [September 30, 2022, 11:47pm UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473/1 "2022-09-30T23:47:21Z")

</div>

JS implicit copy or reference variable depend on thair type in function call. This new syntax essentially uniformize argument call behaviour. Moreover, it add an explicit syntax to change scope variable (eg.: for globals variables used by function of if blocks)  
It:

- Prevent hidden behaviour
- Simplify syntax for varaible copy (structuredClone)
- Better variable lifetime trace (possible optimisation for implementers)

## Syntax

This syntax introduce 2 new keywords

- move (move permanently a variable from a parent scope to a new child scope)
- copy (copy a variable from a parent scope to a new child scope)

Referenced variable can't be moved to prevent access to released memory space

If function use a key word in the declaration it is mandatory at call

### Notation

Basic usage

```ts
{
    //scope A
    const a = /* any */
    const b = /* any */
    
    foo(move a, copy b) {
        //scope B
        a //can be accessed
        b //can be accessed
    }
    
    a //reference error, a is not referenced
    b //can be accessed

    if (move b !== undefined) {
        foo(move b)
        b //reference error, b is not referenced
    }

    b //reference error, b is not referenced

}

```

Function declaration

```ts
function foo(move arg0, copy arg1, arg2) {
    //
}

const a, b, c = [1, 2, 3]

```

Keyword are mandatory if declared in function arguments

Respecting keywords

```ts
foo(move a, copy b, c) //ok

```

Copy to move "cast"

```ts
foo(copy a, copy b, c) //ok, copy encapsulate move for call

```

Move to copy "cast"

```ts
foo(move a, move b, c) //ok, move equivalent to copy for call

```

To keywordless declaration "cast"

```ts
foo(move a, copy b, copy c) //ok
foo(move a, copy b, move c) //ok

```

No keyword to move "cast"

```ts
foo(a, copy b, c) //throws, foo require ownership for arg0

```

No keyword to copy "cast"

```ts
foo(move a, b, c) //throws, foo require a copy for arg1 (ensure non mutation of b)

```

### Rules

`copy a` is equivalent to `structuredClone(a)`  
`move a` de-reference a to all the parents scopes

## Examples

### Copy data

```ts
const source = /* any */
const sourceCopy = copy source

```

### If block

```ts
let value

if (move value = foo()) {
    //do stuff
}

value //out of scope

```

### Legacy muting methods

```ts
const a = [1, 2, 3]

const b = (copy a).reverse()

//a is unchanged

```

### Ressource access prevent

```ts
const ressource = /* */

function release(move ressource) {
    ressource.release()
}

release(move ressource)

//ressource not accessible anymore

```

#### Proposal: [https://github.com/JOTSR/proposal\_explicit\_ownership\_syntax`](https://github.com/JOTSR/proposal_explicit_ownership_syntax%60)

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [October 1, 2022, 12:05am UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473/2 "2022-10-01T00:05:05Z")

</div>

I'm not sure what you mean - JS is always strictly pass by value for every type of value, see [https://web.archive.org/web/20161005155047/http://www.jon-carlos.com/2013/is-javascript-call-by-value-or-call-by-reference/](https://web.archive.org/web/20161005155047/http://www.jon-carlos.com/2013/is-javascript-call-by-value-or-call-by-reference/) for an explanation.

---

<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:** [October 1, 2022, 12:11am UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473/3 "2022-10-01T00:11:11Z")

</div>

Yes, primitive are passed bt value and object by reference, but since JS is not strictly typed you can pass an object ass argument and the execution will not throws on reference/value choice but on possibly type error. Here is a soluction to enforce a reference passing call (that also works for primitive). Moreover, it suggest a syntax to give non mutable reference, since third party function can mutate object and cause difficult to see behaviours.

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [October 1, 2022, 12:37am UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473/4 "2022-10-01T00:37:00Z")

</div>

No, objects are also only passed by value. "pass by reference", as the article explains, refers to _direct_ assignment (and not property mutation).

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [October 1, 2022, 3:20am UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473/5 "2022-10-01T03:20:54Z")

</div>

This sounds fairly Rust inspired. While it would be awesome if we could bring some of these behaviors over to JavaScript, I don't think they translate well, and I don't think there's a practical way to make them translate. There's a few reasons for this:

1. StructuredClone isn't a great general-purpose cloning algorithm. Indeed, I don't believe it's possible to create a good, safe, general-purpose cloning algorithm in JavaScript. For example, if I create a custom Map class, which I'll call MyMap, and I pass an instance of it into structuredClone, it will lose all of its methods and its private state will be inaccessible (I presume that's just thrown away as well). Any objects with functions can't be cloned either.
2. Move semantics work great in Rust, because they're part of a whole system that can provide guarantees that, once you move ownership into a function, no one else can touch that resource. Every piece of code that has been written in Rust has been written in this framework where memory must be managed this way. This isn't the case in JavaScript. In JavScript, I could trivially bypass the guarantees of the move semantics by taking my resource stored in a local variable and putting it on, lets say, globalThis. Later, I "move" my local variable in a function, and lose my ability to use that local variable, but I still have access to the resource via globalThis, and I can still mutate it all I want. I used globalThis as an example, but it could be any object that's being stored in an outer scope, like at the module-level.

You could prevent issue 2 by layering on new rules, like, I must prove that I have full control of the resource, and there aren't references to it hanging out in other places. But, its really too late to do that sort of thing. My code might create a local variable, pass it into one third party library, then pass it into your newer library that has the "move" semantics (e.g. "const resource = ...; thirsPartyLib(resource); yourLib(move resource);`). These "move" semantics require me to prove that there isn't another mutable reference to this variable hanging around somewhere, but I have no way to prove this, because the first library could have very well captured the variable and stored it, and I can't do anything to prove that it hasn't done this.

---

<div class="post-metadata">

**Author:** ![jithujoshyjy](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jithujoshyjy/32/399_2.png) [@jithujoshyjy](https://es.discourse.group/u/jithujoshyjy)\
**Post date:** [October 1, 2022, 6:57am UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473/6 "2022-10-01T06:57:59Z")

</div>

I guess you can have the same behaviour currently with objects and proxies / getter, setters.

Setting the value of a property to null after the initial 'get'.

---

<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:** [October 1, 2022, 9:56am UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473/7 "2022-10-01T09:56:16Z")

</div>

The structuredClone as alias was an example of the behaviour, but yes this algorithm is not suited for that. Can't a low level memory copy be used in runtime inmplementations ? Some Object seems to be hard to copy, maybe a call to new static Object method or Object.prototype named for example "toCopy" that be called by the keyword and that to be surgarged by specific structure and thorws else (the same with move and a "toMove"). Maybe a lazy copy that check ownership at property call or a proxy ?

For the move keyword, object that reference a non anonymous variable can be disallow (eg.: Type error, "var" as no ownership to "reference")

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [October 1, 2022, 6:40pm UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473/8 "2022-10-01T18:40:36Z")

</div>

In this proposed deep-clone algorithm, how would it handle things like:

- prototypes? If I have, for example, an instance of a userland MyUser class, and I deep-clone my instance, will it still use MyUser.prototype as its prototype? What if I deep clone MyUser itself, how would that behave?
- Closures? if I clone a function that has captured variables from the outer scopes, will it also deep-clone those captured variables?
- How would you handle scenarios where, for example, a userland class keeps track of all instances made of it in some static "instances" property. There's no reasonable way to make the deep clone understand that it needs to auto-add the instance to this static "instances" property.

---

<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:** [October 2, 2022, 5:19pm UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473/9 "2022-10-02T17:19:19Z")

</div>

In first, copying only refers to the "intrinsic" value, not a reference. So, a simple approach can be to:

1. Primitives: copy the value
2. Object:  
a. copy own properties and refers the prototype  
b. Throws if no ownership on a value (eg: parent scope value that have not be moved with `move` or copyied with `copy` to avoid performance leak, memory race and long recursion copy.  
c. Recurse from (1.)

Another implementation can be to, for example in V8, duplicate JS Object and recurse on all properties and elements and for JS Function copy all JS Object and JS Function in Context and recurse until global context (that can be make lazy). But it relieves on runtime implementation and not TC39 normalization I think.

As mentioned before, we can also, for Object, implicitly call a copy function (static of Object or in prototype) that can be surcharged.

---

<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:** [October 2, 2022, 5:59pm UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473/10 "2022-10-02T17:59:50Z")

</div>

The goal is to have a unique syntax to move or copy primitives or objects and declare mandatory explicit behavior for callers. In addition to normalize syntax of such manipulations it can also, in a second time and independently from TC39, allow optimization in engine and flow safety for js supersets (e.g. typescript)

---

<div class="post-metadata">

**Author:** ![MaxGraey](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/maxgraey/32/651_2.png) [@MaxGraey](https://es.discourse.group/u/MaxGraey)\
**Post date:** [October 6, 2022, 6:25am UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473/11 "2022-10-06T06:25:17Z")

</div>

I think it's worth giving a link to the original idea?

> **[GitHub - alshdavid/BorrowScript: TypeScript with a Borrow Checker....](https://github.com/alshdavid/BorrowScript#ownership-operators)**
>
> TypeScript with a Borrow Checker. Multi-threaded, Tiny binaries. No GC. Easy to write. - GitHub - alshdavid/BorrowScript: TypeScript with a Borrow Checker. Multi-threaded, Tiny binaries. No GC. Eas...

As for everything else:

> Prevent hidden behavior

JS is pretty explicit. All plain types such as Number or Boolean passed by value (as in all languages). Everything else is passed by reference;

> Simplify syntax for varaible copy (structuredClone).

`structuredClone` is a very specific thing, used very rarely. For example, for passing objects to WebWorker.

> Better variable lifetime trace (possible optimisation for implementers)

JavaScript is GC-based Moreover, many optimizations like escape analysis don't need explicit lifetime marking at all.

All this would only add verbosity and increase the entry threshold, with no obvious benefits

---

<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:** [January 31, 2023, 8:35pm UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473/12 "2023-01-31T20:35:00Z")

</div>

Thanks for referencing this project but I didn't know this project when I post this proposal

---

<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:** [January 31, 2023, 8:38pm UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473/13 "2023-01-31T20:38:24Z")

</div>

For testing purpose here a simple [live example](https://github.com/JOTSR/proposal_explicit_ownership_syntax/tree/main/src/demo) to taste this syntax. For complexity reason it only support clone since move need to check scope tree structure at assignement and so need some work on the js compiler

---

<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:** [January 31, 2023, 8:42pm UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473/14 "2023-01-31T20:42:27Z")

</div>

I propose to solve this issue with a new cloner protocol. Snippet below, full code [here](https://github.com/JOTSR/proposal_explicit_ownership_syntax/blob/3a27dbcd385211ea3d7463a1f99a0034e9605c4b/src/demo/polyfill/clone.ts)

```javascript
Object.prototype[Symbol.cloner] = function () {
	//Copy primitives and null except Symbol
	if (ClonablePrimitives.includes(typeof this) || this === null) {
		return this
	}

	//Throw if not a literal object
	if (Object.getPrototypeOf(this).constructor.name !== 'Object') {
		throw new CloneError(`${this} does not implement [Symbol.cloner]`)
	}

	const clone: Record<string, unknown> = {}

	for (const [property, descriptor] of Object.entries(
		Object.getOwnPropertyDescriptors(this)
	)) {
		try {
			//Recursive clone, not suited for circular references
			clone[property] = descriptor.value[Symbol.cloner]()
		} catch (e) {
			//@ts-ignore cause in Error
			throw new CloneError(`property [${property}] is not cloneable`, {
				cause: e,
			})
		}
	}

	return clone as unknown as typeof this
}

```

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [January 31, 2023, 8:59pm UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473/15 "2023-01-31T20:59:30Z")

</div>

Anything put on Object.prototype won't work with null objects (`Object.create(null)`, `{ __proto__ : null }`, etc), and is a nonstarter with the committee.

(Also, please don't ever install anything onto objects you don't own outside of a spec-compliant polyfill)

---

<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, 12:15pm UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473/16 "2023-02-01T12:15:01Z")

</div>

It is only a simple live exemple. It don't support all use case or pretend to explicitely describe a possible implementation, so `null` and `undefined` are not handled, `Symbol.for` neither and pimitives are cloned via their object instead of direct copy. A good demo should have been done by tweaking a js parser but it will take me a lot of time for a first taste of this idea.

> [@ljharb](#):
>
> (Also, please don't ever install anything onto objects you don't own outside of a spec-compliant polyfill)

I don't understand this remark, Is for the demo on "Map, Array, Date, ...". As it is only a live example it is not to intend any modification outside the scope of this proposal. (Maybe I miss the meaning as I'm not a native english speaker)

---

<div class="post-metadata">

**Author:** ![mhofman](https://avatars.discourse-cdn.com/v4/letter/m/f14d63/32.png) [@mhofman](https://es.discourse.group/u/mhofman)\
**Post date:** [February 1, 2023, 1:37pm UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473/17 "2023-02-01T13:37:03Z")

</div>

I don't see how you could introduce linear types in JS without requiring a new variable declaration to implement those semantics (let's call it `linearLet`). And that only solves the problem for holding an object reference. Let's assume there was a syntax addition to express `move` when invoking functions or returning results from a function, that leaves out property access, which includes method invocation. How do you prevent duplicating a reference to the property of an object held in a `linearLet`? And how do you allow method calls on these objects (after-all methods are just function values held in the object's property)? Even if you somehow can get the method and invoke it, does the method call have access to the object as `this`?

As I've stated in the other thread, I believe it's not possible to implement linear types in a dynamic language like JavaScript.

---

<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, 3:04pm UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473/18 "2023-02-01T15:04:42Z")

</div>

> [@mhofman](#):
>
> I don't see how you could introduce linear types in JS without requiring a new variable declaration to implement those semantics (let's call it `linearLet`). And that only solves the problem for holding an object reference.

It is more for the [Explicit Reference Syntax](https://es.discourse.group/t/draft-for-a-proposal-of-an-explicit-reference-syntax/1475) but for declaration with the & (read write ref) sigil you can declare an exclusive reference:

```javascript
let &exclusive = new Object()
let otherRef = &exclusive //ref error, value has already a mutable refrence
let @readOnlyRef = &ref //ref error, can't ref a reference (in the same scope, you can pass it as arg)

```

With clone/move you can limit scope access

```javascript
let obj = /* any */
let obj2 = /* any */
function(clone obj, move obj2) {
 //obj is a clone and can be released with function
 //obj2 is moved and can be released with function
}

```

If you mix the 2 syntax you can clone the referenced value (`clone &exclusive` clone the value, not the reference to it).

> [@mhofman](#):
>
> How do you prevent duplicating a reference to the property of an object held in a `linearLet`?

It already was discuss in the reference topic but if it what you said, you can't return a reference since is need a cast to a non ref type (du to return keyword) which is forbidden by the syntax. If you return a moved object, it is like a new object you've got from the function call since the original object is dereferenced.

> [@mhofman](#):
>
> And how do you allow method calls on these objects (after-all methods are just function values held in the object's property)? Even if you somehow can get the method and invoke it, does the method call have access to the object as `this`?

As the object is cloned, there is no problem to call method, it is like a new declared object, the same for moved object but I don't see the issue since the object is not re-referenced in another scope. It has no influence on the lifetime.

---

<div class="post-metadata">

**Author:** ![mhofman](https://avatars.discourse-cdn.com/v4/letter/m/f14d63/32.png) [@mhofman](https://es.discourse.group/u/mhofman)\
**Post date:** [February 1, 2023, 4:03pm UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473/19 "2023-02-01T16:03:21Z")

</div>

> [@JOTSR](#):
>
> you can't return a reference since is need a cast to a non ref type (du to return keyword) which is forbidden by the syntax

```js
let &exclusive = { foo: { bar: 'baz' } };

const foo = exclusive.foo; // is this allowed? If not, why not?

```

> [@JOTSR](#):
>
> As the object is cloned, there is no problem to call method, it is like a new declared object

What does cloning an object with methods mean? Especially if these are closures.

```js
const makeFooContainer = (foo) => ({
  getFoo: () => foo,
});

let &exclusive = makeFooContainer({ bar: 'baz'});

function doStuff(copied) {
  copied.getFoo().bar = 'changed';
}

doStuff(copy exclusive);
console.log(exclusive.getFoo().bar); // 'changed'
// internal state of "copied" object got mutated.

```

---

<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, 6:17pm UTC](https://es.discourse.group/t/draft-of-a-proposal-for-an-explicit-ownership-syntax/1473/20 "2023-02-01T18:17:06Z")

</div>

> [@mhofman](#):
>
> ```javascript
> let &exclusive = { foo: { bar: 'baz' } };
> 
> const foo = exclusive.foo; // is this allowed? If not, why not?
> 
> ```

first "&" is a mandatory sigil so you have to write

```javascript
let &exclusive = { foo: { bar: 'baz' } };

const foo = &exclusive.foo

```

then as foo is like an implicit read-write reference of `&exclusive` and reference is recursive in the sense that they are applied on object and all these props it raise a "ref error: one mutable ref allowed". As discused if the [draft](https://es.discourse.group/t/draft-for-a-proposal-of-an-explicit-reference-syntax/1475) you can't reference an object that allready holding an explicit reference (a parse since the sigil is mandatory) or an implicit reference (at runtime) for ownership reason.

> [@mhofman](#):
>
> What does cloning an object with methods mean? Especially if these are closures.
> 
> ```javascript
> 
> ```

Cloning (and moving) are protocol to implement on object (since deep clone problematic was discussed). Standard global object as to provide an implementation and user defined object herit from "Object" but have to implement their logic. You can see an example of what it could look like (and test it on live example in my github)

> <https://github.com/JOTSR/proposal_explicit_ownership_syntax/blob/3a27dbcd385211ea3d7463a1f99a0034e9605c4b/src/demo/polyfill/clone.ts>
