New Proposal: Placeholder syntax

# Andrew Kaiser (5 years ago)

I have created a short proposal to introduce syntactic sugar for anonymous functions in a 'scala-like' manner, linked here andykais/proposal-placeholder-syntax.

I am hoping to hear feedback on whether or not this is interesting to people, as well as feedback on the proposal itself (e.g. is there a better operator to use than *)

# Jordan Harband (5 years ago)

You may be interested in the partial application proposal: tc39/proposal

# Andrew Kaiser (5 years ago)

Do you see a way these proposals can work together? I believe they are solving different needs. Both proposals produce a new anonymous function, but partial application deals with currying, while the placeholder proposal tries to prevent writing a function at all. I can actually see the two working together:

const filenames = ['file1.txt', 'file2.txt' 'output.log' ]
const fileContainsContent = (filename, content) =>
  fs.readFileSync(filename).toString().includes(content)

const fileSearchers = filenames.map(fileContainsContent(*, ?))
const filesContainingSearch = fileSearchers.filter(searcher =>
  searcher('foobar'))

This isn't a very useful example, but you can see how the proposals accomplish different things

# Jordan Harband (5 years ago)

It seems like the partial application proposal covers all of the use cases of yours, at a first glance. What does yours offer that partial application does not?

# Andrew Kaiser (5 years ago)

This proposal also works with simple math operations and for accessing fields on objects. The partial application lists these expressions as invalid.

// invalid
f(x + ?)          // `?` not in top-level Arguments of call
x + ?             // `?` not in top-level Arguments of call
?.f()             // `?` not in top-level Arguments of call

Admittedly they chose not to include these operations because of the complexity it would add to the transpilation, but the placeholder proposal is simpler in nature. The partial application proposal alters what is returned by a function call, the placeholder proposal replaces an argument inline, and the value a called function returns does not change.

# Tab Atkins Jr. (5 years ago)

Aside from the fact that this "placeholder" proposal addresses the "receiver" and "operator" cases that partial-application explicitly omits, the two proposals are exactly identical. They're not "complementary", they're the same thing, just making a different decision wrt complexity of some of the syntax cases.

# Claude Pache (5 years ago)

Le 28 nov. 2018 à 19:17, Andrew Kaiser <kaisea.rpi at gmail.com> a écrit :

Hi all,

I have created a short proposal to introduce syntactic sugar for anonymous functions in a 'scala-like' manner, linked here andykais/proposal-placeholder-syntax, andykais/proposal-placeholder-syntax.

I am hoping to hear feedback on whether or not this is interesting to people, as well as feedback on the proposal itself (e.g. is there a better operator to use than *)

See the previous discussion on this topic:

esdiscuss.org/topic/syntax

# Ron Buckton (5 years ago)

Partial application chose to limit the scope of ? to argument positions in an argument list for a number of reasons. The primary being this case (assuming arbitrary expressions were allowed):

let i = 0;
const g = f({ x: i++, y: ? });

The goal of partial application was to “fix” non-placeholder arguments at the time the partial function result is bound. This means that i++ above should evaluate only once. However, if we allowed placeholders in arbitrary parts of an expression, to preserve this behavior we would have to be able to “partially fix” any arbitrary expression (such as the property names and property values of the object literal above). Various committee members indicated that they were very much opposed to this kind of partial fixing.

The other problem with placeholders is scoping. The above example could have two interpretations: One where g is a partial function for f with an argument that fills in the y property, and one where f is called with an object that has a property y that is an identity function.

A placeholder as an arbitrary expression is also complicated by something like g(f(?)). If ? is an arbitrary expression, you need to syntactically mark the boundary of the expression, otherwise a user could expect the result to be either x => g(f(x)) or g(x => f(x)). In Scala’s case, you end up needing to use a block-style for these cases. If ? is scoped to its immediate argument list and does not allow arbitrary expressions, then there becomes only one possible interpretation (in this case, g(x => f(x))). In this way, partial application is like a more powerful syntactic variation of Function.prototype.bind, as Function.prototype.bind always fixes arguments in the function’s immediate argument list.

Ron

From: es-discuss <es-discuss-bounces at mozilla.org> On Behalf Of Andrew Kaiser

Sent: Wednesday, November 28, 2018 11:57 AM To: ljharb at gmail.com Cc: es-discuss at mozilla.org Subject: Re: New Proposal: Placeholder syntax

This proposal also works with simple math operations and for accessing fields on objects. The partial application lists these expressions as invalid.

// invalid
f(x + ?)          // `?` not in top-level Arguments of call
x + ?             // `?` not in top-level Arguments of call
?.f()             // `?` not in top-level Arguments of call

Admittedly they chose not to include these operations because of the complexity it would add to the transpilation, but the placeholder proposal is simpler in nature. The partial application proposal alters what is returned by a function call, the placeholder proposal replaces an argument inline, and the value a called function returns does not change.

On Wed, Nov 28, 2018 at 2:35 PM Jordan Harband <ljharb at gmail.com<mailto:ljharb at gmail.com>> wrote:

It seems like the partial application proposal covers all of the use cases of yours, at a first glance. What does yours offer that partial application does not?

On Wed, Nov 28, 2018 at 11:23 AM Andrew Kaiser <kaisea.rpi at gmail.com<mailto:kaisea.rpi at gmail.com>> wrote:

Do you see a way these proposals can work together? I believe they are solving different needs. Both proposals produce a new anonymous function, but partial application deals with currying, while the placeholder proposal tries to prevent writing a function at all. I can actually see the two working together:

const filenames = ['file1.txt', 'file2.txt' 'output.log' ]
const fileContainsContent = (filename, content) => fs.readFileSync(filename).toString().includes(content)

const fileSearchers = filenames.map(fileContainsContent(*, ?))
const filesContainingSearch = fileSearchers.filter(searcher => searcher('foobar'))

This isn't a very useful example, but you can see how the proposals differ accomplish different things

On Wed, Nov 28, 2018 at 1:30 PM Jordan Harband <ljharb at gmail.com<mailto:ljharb at gmail.com>> wrote:

You may be interested in the partial application proposal: tc39/proposal-partial-applicationna01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Ftc39%2Fproposal-partial-application&data=02|01|ron.buckton%40microsoft.com|3f77a64eda334aa76bd708d6556ba4d0|72f988bf86f141af91ab2d7cd011db47|1|0|636790318211957611&sdata=Esl%2F8p6N7B8pJuXqyycMfmhIB38h67zrAwj9CzQLieU%3D&reserved=0

On Wed, Nov 28, 2018 at 10:17 AM Andrew Kaiser <kaisea.rpi at gmail.com<mailto:kaisea.rpi at gmail.com>> wrote:

Hi all,

I have created a short proposal to introduce syntactic sugar for anonymous functions in a 'scala-like' manner, linked here andykais/proposal-placeholder-syntaxna01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fandykais%2Fproposal-placeholder-syntax&data=02|01|ron.buckton%40microsoft.com|3f77a64eda334aa76bd708d6556ba4d0|72f988bf86f141af91ab2d7cd011db47|1|0|636790318211967623&sdata=UPfh4NQUw38f03Qq92xZWVj2%2BEH3esAg6SXhHzXd51U%3D&reserved=0.

I am hoping to hear feedback on whether or not this is interesting to people, as well as feedback on the proposal itself (e.g. is there a better operator to use than *)

# Herbert Vojčík (5 years ago)

I find the "receiver" usage actually pretty useful. I know how I like to be able to do something like

Smalltalk packages do: #commit

in Amber Smalltalk (even if it would be only a few chars longer

Smalltalk packages do: [ :each | each commit ]

but readability is different, b/c the spirit of it is different, latter being explicitly imperative).

If partial application would win (why not), I would like to come up with receiver case as well in some other way. For example as:

.x / .f()

instead of

each => each.x / each => each.f()

IOW, would it be at least possible to sort-of future-proof ".xyz" for this kind of use?

# Waldemar Horwat (5 years ago)

On 11/28/2018 10:17 AM, Andrew Kaiser wrote:

Hi all,

I have created a short proposal to introduce syntactic sugar for anonymous functions in a 'scala-like' manner, linked here andykais/proposal-placeholder-syntax.

I am hoping to hear feedback on whether or not this is interesting to people, as well as feedback on the proposal itself (e.g. is there a better operator to use than *)

This is error-prone:

const sum = numbers.reduce(? + ?) transforms into const sum = numbers.reduce((x, y) => x + y)

but then:

const identity = numbers.reduce(?) transforms into const identity = (x) => numbers.reduce(x)

instead of the analogous const identity = numbers.reduce((x) => x)

And what would const z = numbers.reduce(? + ? > 0)

or const z = numbers.reduce(2*(? + ?)) or const z = numbers.reduce(foo(? + ?)) transform into?

 Waldemar
# Andrew Kaiser (5 years ago)

thank you all for the feedback, I appreciate those who pointed out the flaws in the logic. I can see that this is an ambiguous proposal. Though I did not realize it at the time, this proposal is competing with tc39/proposal-partial-application, as the two syntax's cannot exist in the same language. I still find the scala-like pattern useful, and not all hope is lost. There is a babel macro www.npmjs.com/package/param.macro which was inspired by scala's _.

Side note, they solve the issue of g(f(?)) creating either x => g(f(x)) or g(x => f(x)) by splitting the logic into two different macros: it and _.

import { _, it } from 'param.macro'

const arrayOfObj = [{ n: 1 }, { n: 2 }, { n: 3}]

arrayOfObj.map(it.n)
// yeilds
// arrayOfObj.map(x => x.n)

arrayOfObj.map(_.n)
// yeilds
// x => arrayOfObj.map(x.n)

If anyone is interested in keeping the proposal alive/modifying it, feel free to put a pull request on my repo andykais/proposal-placeholder-syntax. Otherwise, I don't believe I see a lot of interest in it according to this discussion.