Skip to content

Commit e3bf65a

Browse files
authored
Named Arguments Syntax ({{@foo}}) (rust-lang#276)
1 parent d3fbe98 commit e3bf65a

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

text/0276-named-args.md

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
- Start Date: 2017-12-10
2+
- RFC PR: https://github.com/emberjs/rfcs/pull/276
3+
- Ember Issue: https://github.com/emberjs/ember.js/pull/15968
4+
5+
# Summary
6+
7+
Introduce `{{@foo}}` in as a dedicated syntax for a component's template to
8+
refer to named arguments passed in by the caller.
9+
10+
For example, given the invocation `{{hello-world name="Godfrey"}}` and this
11+
component template in `app/templates/components/hello-world.hbs`:
12+
13+
```hbs
14+
Hello, {{@name}}
15+
```
16+
17+
Ember will render "Hello, Godfrey".
18+
19+
# Motivation
20+
21+
Currently, the way to access named arguments passed in from the caller is to
22+
reference `{{name}}` in the template. This works because when Ember creates
23+
the component instance, it automatically [assigns](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
24+
all named arguments as properties on the component instance.
25+
26+
The first problem with this approach is that the `{{name}}` syntax is highly
27+
ambigious, as it could be referring to a local variable (block param), a
28+
helper or a named argument from the caller (which actually works by accessing
29+
auto-reflected `{{this.name}}`) or a property on the component class (such as
30+
a computed property).
31+
32+
This can often lead to confusion for readers of the template. Upon encountering
33+
`{{foo}}` in a component's template, the reader has to check all of
34+
these places: first you need to scan the surrounding lines for block
35+
params with that name; next you check in the helpers folder to see it there
36+
is a helper with that name (it could also be coming from an addon!); then you
37+
check if it is an argument provided by the caller; finally, you check the
38+
component's JavaScript class to look for a (computed) property. If you _still_
39+
did not find it, maybe it is a named arguments that is passed only sometimes,
40+
or perhaps it is just a leftover reference from a previous refactor?
41+
42+
Providing a dedicated syntax for referring to named arguments will resolve the
43+
ambiguity and greatly improve clarity, especially in big projects with a lot
44+
of files (and uses a lot of addons). (The existing `{{this.name}}` syntax can
45+
already be used to disambiguate component properties from helpers.)
46+
47+
As an aside, the ambiguity that causes confusion for human readers is also a
48+
problem for the compiler. While it is not the main goal of this proposal,
49+
resolving this ambiguity also helps the rendering system. Currently, the
50+
"runtime" template compiler has to perform a helper lookup for every `{{name}}`
51+
in each template. It will be able to skip this resolution process and perform
52+
other optimizations (such as reusing the internal [reference](https://github.com/glimmerjs/glimmer-vm/blob/master/guides/04-references.md)
53+
object and caches) with this addition.
54+
55+
Another problem with the current approach of automatically "reflecting" named
56+
arguments on the instance is that they can unexpectedly overwrite other
57+
properties defined on the component's class. It also defeats performance
58+
optimizations in JavaScript engines as this approach creates many different
59+
polymorphic "shapes" for instances that otherwise belong to the same
60+
component class.
61+
62+
While this proposal does not directly solve this problem (we are not proposing
63+
that we deprecate or remove the "auto-reflection" on `Ember.Component`), it
64+
paves the way for a future world where components can work without them.
65+
66+
Notably, the current iteration of the [Glimmer Components](https://glimmerjs.com/guides/templates-and-helpers)
67+
have adopted this design for over a year now and the experience has been very
68+
positive. This would be one of the first pieces (admittedly, only a tiny piece)
69+
of the Glimmer.js experiment to make its way into Ember. We think this feature
70+
is small, self-contained but useful enough to be the ideal candidate to kick
71+
off this process.
72+
73+
# Detailed design
74+
75+
This feature was baked into the Glimmer VM very early on. In fact, the
76+
only thing that is stopping them from working in Ember is [an AST transform](https://github.com/emberjs/ember.js/blob/87be17d8e69f83b2abed8c0695f8fa5e4bcae473/packages/ember-template-compiler/lib/plugins/assert-reserved-named-arguments.js)
77+
that specifically disallows them. Therefore, "implementing" this feature is
78+
just a matter of deleting that file.
79+
80+
Additionally, the legacy `{{attrs.foo}}` syntax (which more or less tries to
81+
accomplish the same thing) has actually been [implemented using `{{@foo}}`](https://github.com/emberjs/ember.js/blob/87be17d8e69f83b2abed8c0695f8fa5e4bcae473/packages/ember-template-compiler/lib/plugins/transform-attrs-into-args.js)
82+
under-the-hood since Ember 2.10.
83+
84+
## Reserved Names
85+
86+
We will reserve `{{@args}}`, `{{@arguments}}` and anything that does not
87+
start with a lowercase letter (such as `@Foo`, `@0`, `@!` etc) in the first
88+
version. This is purely speculative and the goal is to carve out some space
89+
for future features. If we don't end up needing them, we can always relax
90+
the restrictions down the road.
91+
92+
# How We Teach This
93+
94+
`{{@foo}}` is the way to access the named arguments passed from the caller.
95+
96+
Since the `{{foo}}` syntax still works on `Ember.Component` (which is the
97+
only kind of components available today) via the auto-reflection mechanism,
98+
we are not really in a rush to migrate the community (and the guides, etc)
99+
to using the new syntax. In the meantime, this could be viewed as a tool to
100+
improve clarity in templates, similar to how the optional "explicit `this`"
101+
syntax (`{{this.foo}}`).
102+
103+
While we think writing `{{@foo}}` would be a best practice for new code
104+
going forward, the community can migrate at its own pace one component at a
105+
time.
106+
107+
We can also encourage the community to supplement this effort by wiring
108+
linting tools and code mods.
109+
110+
# Drawbacks
111+
112+
This introduces a new piece of syntax that one would need to learn in order to
113+
understand Ember templates.
114+
115+
This mostly affects "casual" readers (as this should be very easy for an Ember
116+
developer to learn, understand and remember after encounting/learning it for
117+
the first time). However, since these casual readers are also among those
118+
who are most acutely affected by the ambiguity, we believe this is still a
119+
net improvement over the status-quo.
120+
121+
# Alternatives
122+
123+
We have `{{attrs.foo}}` today. In React, there is `this.props.foo`.
124+
125+
Given how common this is, we think it deserves its own dedicated, succinct
126+
syntax. The other alternatives that involve reflecting them on the component
127+
instances also would not allow for the internal optimizations in the Glimmer
128+
VM.

0 commit comments

Comments
 (0)