Skip to content

Commit

Permalink
Change -> to ::
Browse files Browse the repository at this point in the history
See #10.
  • Loading branch information
js-choi committed Oct 6, 2021
1 parent b19fcc7 commit 12a983c
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 87 deletions.
70 changes: 35 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,21 @@ For more information, see [§ Related proposals](#related-proposals).
## Description
(A [formal specification][] is available.)

Method binding `->` is a **left-associative** binary operator.
Method binding `::` is a **left-associative** binary operator.
Its right-hand side is an **identifier** (like `f`)
or a parenthesized **expression** (like `(hof())`),
either of which must evaluate to a **function**.
Its left-hand side is some expression that evaluates to an **object**.
The `->` operator binds its left-hand side
The `::` operator binds its left-hand side
to its right-hand side’s `this` value,
creating a **bound function** in the same manner
as [`Function.prototype.bind`][bind].

For example, `arr->fn` would equivalent to `fn.bind(arr)`
For example, `arr::fn` would be equivalent to `fn.bind(arr)`
(except that its behavior does not change
if code elsewhere reassigns the global method `Function.prototype.bind`).

Likewise, `obj->(createMethod())` would be roughly
Likewise, `obj::(createMethod())` would be roughly
equivalent to `createMethod().bind(obj)`.

If the operator’s right-hand side does not evaluate to a function during runtime,
Expand All @@ -44,7 +44,7 @@ that are already created by [`Function.prototype.bind`][bind].
Both are **exotic objects** that do not have a `prototype` property,
and which may be called like any typical function.

From this definition, `o->f(...args)`
From this definition, `o::f(...args)`
is also **indistinguishable** from `f.call(o, ...args)`
(except that its behavior does not change
if code elsewhere reassigns the global method `Function.prototype.call`).
Expand All @@ -59,23 +59,23 @@ by optional chains in its left-hand side.

| Left-hand side | Example | Grouping
| ---------------------------------- | ------------ | --------------
| Member expressions |`a.b->fn.c` |`((a.b)->fn).c`
| Call expressions |`a()->fn()` |`((a())->fn)()`
| Optional chains |`a?.b->fn` |`(a?.b)->fn`
|`new` expressions with arguments |`new C(a)->fn`|`(new C(a))->fn`
|`new` expressions without arguments*|`new a->fn` |`new (a->fn)`
| Member expressions |`a.b::fn.c` |`((a.b)::fn).c`
| Call expressions |`a()::fn()` |`((a())::fn)()`
| Optional chains |`a?.b::fn` |`(a?.b)::fn`
|`new` expressions with arguments |`new C(a)::fn`|`(new C(a))::fn`
|`new` expressions without arguments*|`new a::fn` |`new (a::fn)`

\* Like `.` and `?.`, the `this`-bind operator also have tighter precedence
than `new` expressions without arguments.
Of course, `new a->fn` is not a very useful expression,
Of course, `new a::fn` is not a very useful expression,
just like how `new (fn.bind(a))` is not a very useful expression.

Similarly to the `.` and `?.` operators,
the `->` operator may be **padded by whitespace**.\
For example, `a -> m`\
is equivalent to `a->fn`,\
and `a -> (createFn())`\
is equivalent to `a->(createFn())`.
the `::` operator may be **padded by whitespace**.\
For example, `a :: m`\
is equivalent to `a::fn`,\
and `a :: (createFn())`\
is equivalent to `a::(createFn())`.

There are **no other** special rules.

Expand Down Expand Up @@ -178,61 +178,61 @@ and they interpose the verb’s `Function.prototype` method between them:
`obj.call(arg)`.

Consider the following real-life code using `.bind` or `.call`,
and compare them to versions that use the `->` operator.
and compare them to versions that use the `::` operator.
The difference is especially evident when you read them aloud.

```js
// [email protected]/index.js
type = toString.call(val);
type = val->toString();
type = val::toString();

// [email protected]/src/common.js
match = formatter.call(self, val);
match = self->formatter(val);
match = self::formatter(val);

createDebug.formatArgs.call(self, args);
self->(createDebug.formatArgs)(args);
self::(createDebug.formatArgs)(args);

// [email protected]/errors-browser.js
return _Base.call(this, getMessage(arg1, arg2, arg3)) || this;
return this->_Base(getMessage(arg1, arg2, arg3)) || this;
return this::_Base(getMessage(arg1, arg2, arg3)) || this;

// [email protected]/lib/_stream_readable.js
var res = Stream.prototype.on.call(this, ev, fn);
var res = this->(Stream.prototype.on)(ev, fn);
var res = this::(Stream.prototype.on)(ev, fn);

var res = Stream.prototype.removeAllListeners.apply(this, arguments);
var res = this->(Stream.prototype.removeAllListeners)(...arguments);
var res = this::(Stream.prototype.removeAllListeners)(...arguments);

// [email protected]/lib/middleware.js
Array.prototype.push.apply(globalMiddleware, callback)
globalMiddleware->(Array.prototype.push)(...callback)
globalMiddleware::(Array.prototype.push)(...callback)

// [email protected]/lib/command.js
[].push.apply(positionalKeys, parsed.aliases[key])

// [email protected]/build-es5/index.js
var code = fn.apply(colorConvert, arguments);
var code = colorConvert->fn(...arguments);
var code = colorConvert::fn(...arguments);

// [email protected]/q.js
return value.apply(thisp, args);
return thisp->value(...args);
return thisp::value(...args);

// [email protected]/src/internal/operators/every.ts
result = this.predicate.call(this.thisArg, value, this.index++, this.source);
result = this.thisArg->(this.predicate)(value, this.index++, this.source);
result = this.thisArg::(this.predicate)(value, this.index++, this.source);

// [email protected]/js/release/synchronous_inspection.js
return isPending.call(this._target());
return this._target()->isPending();
return this._target()::isPending();

var matchesPredicate = tryCatch(item).call(boundTo, e);
var matchesPredicate = boundTo->(tryCatch(item))(e);
var matchesPredicate = boundTo::(tryCatch(item))(e);

// [email protected]/polyfills.js
return fs$read.call(fs, fd, buffer, offset, length, position, callback)
return fs->fs$read(fd, buffer, offset, length, position, callback)
return fs::fs$read(fd, buffer, offset, length, position, callback)
```

[noun–verb–noun word order]: https://en.wikipedia.org/wiki/Subject–verb–object
Expand All @@ -246,7 +246,7 @@ does *not* address the following use cases.
(like `arr&.slice` for `arr.slice.bind(arr.slice)` hypothetically)
would be nice to have,
but method extraction is already possible with this proposal.\
`const slice = arr->(arr.slice); slice(1, 3);`\
`const slice = arr::(arr.slice); slice(1, 3);`\
is not much wordier than\
`const slice = arr&.slice; slice(1, 3);`

Expand All @@ -271,7 +271,7 @@ const { get: $getSize } =
delete Set; delete Function;

// Our own trusted code, running later.
new Set([0, 1, 2])->$getSize();
new Set([0, 1, 2])::$getSize();
```

**Function/expression application**,
Expand All @@ -280,8 +280,8 @@ are untangled into linear pipelines,
is important but not addressed by this proposal.
Instead, it is addressed by the **pipe operator**,
with which this proposal’s syntax works well.\
For example, we could untangle `h(await g(o->f(0, v)), 1)`\
into `v |> o->f(0, %) |> await g(%) |> h(%, 1)`.
For example, we could untangle `h(await g(o::f(0, v)), 1)`\
into `v |> o::f(0, %) |> await g(%) |> h(%, 1)`.

[syntactic salt]: https://en.wikipedia.org/wiki/Syntactic_sugar#Syntactic_salt
[primordials.js]: https://github.com/nodejs/node/blob/master/lib/internal/per_context/primordials.js
Expand Down Expand Up @@ -348,7 +348,7 @@ Object.keys(envars)
// Adapted from [email protected]/index.js
return this._styles
|> (^ ? ^.concat(codes) : [codes])
|> this->build(^, this._empty, key);
|> this::build(^, this._empty, key);
```

[pipe operator]: https://github.com/tc39/proposal-pipeline-operator
40 changes: 20 additions & 20 deletions extensions-comparison.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ There are two proposals that do similar things.

* A [proposal for an extensions system][extensions system]:
`::{ extFn } = obj`, `obj::extFn`, and `obj::extNamespace:extFn`.
* A [proposal for a bind-`this` operator][bind-this]: `obj->fn` and `obj->(fn)`.
* A [proposal for a bind-`this` operator][bind-this]: `obj::fn` and `obj::(fn)`.

In brief, the concrete differences are:

Expand Down Expand Up @@ -52,7 +52,7 @@ does not **[shadow][shadowing]** any other variables.
```js
const $has = Set.prototype.has;

s->$has(1);
s::$has(1);
```
This is **nothing new**:
developers **already** have to be careful with their variables’ names,
Expand Down Expand Up @@ -90,7 +90,7 @@ const { get: getSize } =
Set.prototype, 'size');

// Calls the size getter.
s->getSize();
s::getSize();
```
We would use the getter/setter functions **as usual**
with no special syntax.
Expand Down Expand Up @@ -136,8 +136,8 @@ const { get: $getSize } =
Object.getOwnPropertyDescriptor(
Set.prototype, 'size');

s->$has(1);
s->$getSize();
s::$has(1);
s::$getSize();
```

<tr>
Expand Down Expand Up @@ -192,8 +192,8 @@ delete Set;
delete Function;

// Our own trusted code, running later.
s->$has(1);
s->$getSize();
s::$has(1);
s::$getSize();
```

<tr>
Expand Down Expand Up @@ -285,8 +285,8 @@ const $ = {
getIntrinsic('Set.prototype.size'),
};
const s = new Set([0, 1, 2]);
s->($.has)(1);
s->($.getSize)();
s::($.has)(1);
s::($.getSize)();
```

<tr>
Expand Down Expand Up @@ -330,7 +330,7 @@ let map = new Map();

function foo() {
// $map is verb
a->$map(f);
a::$map(f);
}
```

Expand Down Expand Up @@ -358,10 +358,10 @@ Because it may be an arbitrary expression,
it is both more verbose, more explicit, and more flexible.

```js
s->(Set.has)(1);
s::(Set.has)(1);
// This is equivalent:
const $has = Set.has;
s->$has(1);
s::$has(1);
```

<tr>
Expand Down Expand Up @@ -394,15 +394,15 @@ serving as more [syntactic salt][].
The bind-`this` operator would encourage such clarity and explicitness.

```js
indexed->(Array.prototype.map)(x => x * x);
indexed->(Array.prototype.filter)(x => x > 0);
indexed::(Array.prototype.map)(x => x * x);
indexed::(Array.prototype.filter)(x => x > 0);

const {
map: $map, filter: $filter,
} = Array.prototype;

indexed->$map(x => x * x);
indexed->$filter(x => x > 0);
indexed::$map(x => x * x);
indexed::$filter(x => x > 0);
```

<tr>
Expand Down Expand Up @@ -492,7 +492,7 @@ If we want to convert a static-method call into a postfix chaining form,
we can use the [pipe operator][] again.

```js
obj->(Object.prototype.toString)();
obj::(Object.prototype.toString)();
obj |> Object.keys(^);
```

Expand Down Expand Up @@ -622,8 +622,8 @@ export const at = function (i) {
// Another module
import $at from 'foo';
'Hello world'.split(' ')
->$at(0).toUpperCase()
->$at(-1);
::$at(0).toUpperCase()
::$at(-1);
```
Libraries may export only to the single ordinary variable namespace.
There is therefore little risk of ecosystem schism.
Expand Down Expand Up @@ -665,7 +665,7 @@ const user = {
name: 'hax',
greet () { return `Hi ${this.name}!`; }
};
const f = user->greet;
const f = user::greet;
f(); // 'Hi hax!'
```

Expand Down
Loading

0 comments on commit 12a983c

Please sign in to comment.