vuejs / vue

This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
http://v2.vuejs.org
MIT License
207.12k stars 33.64k forks source link

Make binding syntax more consistent #1173

Closed yyx990803 closed 8 years ago

yyx990803 commented 8 years ago

Quick Reference of Latest Syntax

Last updated: Sep. 11th - 1.0.0-alpha.4

<!-- flow control -->
<div v-if="ok">
<div v-for="item in items">
<div v-show="hi">

<!-- two-way form binding -->
<input v-model="abc">

<!-- literal directive: add hash before equal -->
<a v-link#="/abc/123"></a>

<!-- event handlers -->
 <input
    on-change="handleChange"
    on-focus="handleFocus"
    on-blur="handleBlur">

<!-- key filter for keypress events -->
<input on-keyup-esc="handleEsc">

<!-- normal attribute bindings, make it reactive by adding "bind-" -->
<img bind-src="baseURL + '/avatar/' + username + '.png'">
<a bind-href="'/profile/' + username"></a>

<!-- class & style are enhanced to accept objects and arrays -->

<!-- toggle classes -->
<div bind-class="{ 'class-a': true, 'class-b': false }"></div>
<!-- apply a list of classes -->
<div bind-class="[ dynamicClass, 'literal-class' ]"></div>

<!-- apply style object (camelCase accepted) -->
<div bind-style="{ fontSize: '14px', color: 'red' }"></div>
<!-- apply multiple style objects -->
<div bind-style="[ styleObjectA, styleObjectB ]"></div>

<!-- shorthand for "bind-", just add colon -->
<img :src="...">
<a :href="..."></a>

<!-- component props, also use "bind-" or colon shorthand -->
<!-- without "bind-" or colon it's passed as a literal string -->
<component
  literal="hello"
  bind-dynamic="parentMsg"
  :dynamic="something"
  :two-way@="something"
  :one-time*="something">
</component>

<!-- v-el and v-ref now use dedicated syntax -->

<!-- registers vm.$.child -->
<comp $.child></comp>

<!-- registers vm.$$.node -->
<div $$.node></div>

<!-- caveat: must use dash-case instead of camelCase, similar to props -->
<!-- registers vm.$.someComp -->
<comp $.some-comp></comp>

Context

Currently we have several types of bindings in the template:

  1. Reactive directives, e.g. v-style, v-on & v-repeat. Their attribute values are directly evaluated as expressions in the current component scope, and cannot contain mustache tags.
  2. (Dynamic) Literal directives, e.g. v-transition, v-ref & v-el. Their attribute values are treated as plain strings and can contain mustache tags - but it's not always reactive: only v-transition is reactive when containing mustache tags; the other two evaluate them only once.
  3. Normal HTML attributes with mustache tags. These are converted into v-attr internally.
  4. Prop bindings, e.g. my-prop="{{abc}}". Props' attribute values are treated as plain strings and can contain mustache tags; the prop binding is only dynamic if it contains mustache tags.
  5. Directive param attributes, e.g. transition-mode, track-by, number & debounce. These are treated almost as normal attributes, but evaluated only once.

    Problem

Well, as you probably have noticed, it's confusing! There are many types of attributes and there's no clear rule on where expressions are expected and where mustache interpolations are allowed.

Specifically, the prop syntax could use some improvement. The original intention of making props require mustaches tags to be reactive is so that a dynamic prop can look different from normal HTML attributes. But given that normal attributes can contain mustache tags as well, it's still not explicit enough. It's also much more common to use dynamic props than literal strings, and using mustache tags to indicate reactivity is simply not intuitive.

Another problem is it becomes awkward when you want to pass a literal number/boolean prop, because without mustache tags, the attribute value is just a string. You'd have to write prop="{{123}}" or prop="{{true}}" to pass a real number or boolean. Currently, Vue auto-casts literal props into numbers/booleans if possible, which this may not always be what we want - what if we want to pass in a string of numbers?

Proposal

Last Updated: Sep.11th (1.0.0-alpha.4)

Here's some pretty radical changes (or maybe not), but imo conceptually much cleaner. The goal here is to 1) eliminate {{ }} inside attribute values; and 2) categorize the syntax by their purpose.

  1. Text and HTML interpolations. Handled with {{ }} and {{{ }}}. And this will also be the only places where mustaches are used.
  2. Vue directives. These preserve the v- prefix because they do something special. Binding values are always parsed as expressions. No more arguments or multiple clauses, just one expression followed by one or more filters. Only v-for (previously v-repeat) preserves the item in items special syntax.

    <!-- view logic -->
    <p v-show="ok"></p>
    <p v-if="!ok"></p>
    <p v-for="item in items"></p>
    
    <!-- two-way binding -->
    <input v-model="val">
    
    <!-- empty directives -->
    <div v-cloak></div>
    <div v-pre></div>

    And that's it. Only 6 core directives. (v-text and v-html are also preserved, but they are replaceable by interpolations)

    Literal Syntax

    In 1.0, all core directives are either reactive or empty. But sometimes we may want to pass in a literal string to a custom directive instead of a dynamic expression, similar to 0.12 literal directives. But in 1.0 we want to make this explicit, so we can clearly know whether the attribute value is actually a string or an expression. So, in 1.0 there will no longer be the concept of "literal directives", we use the dot-equal syntax to indicate we are passing a literal value to the directive. The directive's update function will be called once, with the literal string as the argument:

    <a v-link#="/a/b/c">
  3. Event handlers. Prefixed with on-. Value always parsed as expressions, can either be the method name or a statement (e.g. a = !a). I've raised this once before, but people seemed to really like the fact that v-on starts with v-. IMO event handlers deserve something different and more succinct.

    <!-- easier to type, and reads better -->
    <form on-submit="handleSubmit"></form>
    
    <!-- multiple listeners also much cleaner -->
    <input
     on-change="handleChange"
     on-focus="handleFocus"
     on-blur="handleBlur">
    
    <!-- in addition: key filter can be replaced with: -->
    <input on-keyup-enter="doThis" on-keyup-esc="doThat">
  4. Normal attribute bindings. Currently these are done via putting {{ }} inside attribute values. This often leads to people thinking in a string-template fashion and get confused about where {{ }} are allowed and where not. The proposal is to prefix dynamic attribute bindings with the bind- prefix:

    <!-- plain string -->
    <img src="/avatars/123.png">
    
    <!-- bind to expression -->
    <img bind-src="'/avatars/' + userId + '.png'">
    
    <!-- style/class are enhanced to accept object/array values -->
    <div bind-class="classes"></div>
    <div bind-class="[classA, classB]"></div>
    <div bind-class="{ classA: true, classB: false }"></div>
    
    <div bind-style="cssString"></div>
    <div bind-style="{ fontSize: fontSize, color: currentColor }"></div>
    <div bind-style="[styleObjectA, styleObjectB]"></div>

    In addition, the bind- prefix can be shortened as a colon, which is totally optional:

    <img :src="'/avatars/' + userId + '.png'">
  5. Props. Similar to normal attribute bindings, non-prefixed props are always passed down as literal strings; To pass a dynamic prop, add bind- or colon prefix.

    Also, binding type indicators are now moved from the attribute value into the attribute name, right before the equal sign.

    <example
     literal="Mike"
     bind-dynamic="someThing"
     bind-onetime*="onlyOnce"
     bind-twoway@="syncsBackUp"
     :shorthand="sameAsBind">
    </example>
  6. Special attributes (including both directive params & literal directives). These will only appear together with either a directive or a component. You can also use bind- or colon prefixes for these, but only is, ref, el and transition will have reactive behavior, other directive params are evaluated only once (Vue will tell you in dev mode).

    <component
     :is="view"
     transition="slide"
     transition-mode="out-in">
    </component>
  7. Child component and element refs (previously v-ref and v-el) are no longer directives. They now have their own dedicated syntaxes. (see #1292)

    The benefits:

  8. Explicit. The code says what it does.
  9. Simpler. Smaller set of core directives. No more "args" for directives; no more multiple clauses; It's just expressions + filters.
  10. No more confusion about mustache inside attributes. If you see a v-, on- or bind- prefix, it always means the value is an expression. If there's no prefix, then it's a always a plain string!
  11. Eliminates edge cases like src="{{abc}}" causing 404 requests and style="{{something}}" gets thrown away in IE. Also eliminates the need for v-attr.

    Note

Please don't dislike this proposal just for the sake of "why so many changes"; all the changes proposed here can be implemented in a backwards compatible way in 1.0.0-alpha (with deprecation warnings) and migration should not be unacceptably painful.

azamat-sharapov commented 8 years ago

and probably data- will become synonym to prop-?

yyx990803 commented 8 years ago

@azamat-sharapov probably not, because some libs rely on data- attributes, we don't know if the user really wants a data attribute or a prop.

vitorarjol commented 8 years ago

I really like this proposal, and, to me, in that way the code speaks for itself and looks even cleaner. :+1:

Mat-Moo commented 8 years ago

Whilst I agree, I like the fact that it is v- becasue then it's easy to understand it's a VUE based attribute rather than third party or anything else. Could this be a config value, becasue I would quite like to use u- (still leaves e- !) so that when looking at the thml you know it's part of the vue system?

yyx990803 commented 8 years ago

@Mat-Moo most of the literal directives need to be used together with other reactive directives. e.g. v-transition only makes sense when there's also v-if, v-repeat or when it is a component; v-ref can also only be used on v-repeat and components. They should've been treated more like directive params in the beginning (which are non-prefixed). v-el is an exception, and I actually never liked it since you can always just do a querySelector (considering deprecating it in 1.0).

Mat-Moo commented 8 years ago

@yyx990803 Actually I suppose that makes it consistent with props for a component

104gogo commented 8 years ago

@yyx990803 hello,how can I use 'v-on' directive on one tag and bind more than one event, like the question 4 above,please give me some suggests.forgive my poor english.

azamat-sharapov commented 8 years ago

@104gogo http://vuejs.org/guide/directives.html#Multiple_Clauses

104gogo commented 8 years ago

@azamat-sharapov thx!!

davidkhess commented 8 years ago

I like this proposal – especially if we can get to it in a non-breaking way with deprecation warnings.

It is indeed confusing keeping track of where and when literals, dynamic literals and expressions all apply.

gapipro commented 8 years ago

Overall this simplifies understanding of code.

Only thing I personally don't like is bullet 5. {{ something }} syntax is sometimes very clean and easy to understand.

Example:

<div class="ui button {{color}}">Sample Button</div>

How do you achieve same result with new syntax?

yyx990803 commented 8 years ago

@gapipro I agree - string concatenation can be a bit ugly with only bind- syntax:

<div bind-class="'ui button ' + color">Sample Button</div>
davidkhess commented 8 years ago

But wouldn't v-class be the more appropriate way to handle this particular case? How many other attributes behave like class?

yyx990803 commented 8 years ago

@davidkhess Yeah, it could be something like this:

<div class="ui button" v-class="color">Sample Button</div>

But still not as clear as the interpolation syntax :/

davidkhess commented 8 years ago

I don't know - I personally prefer v-class since it is more explicit about what is going on.

yyx990803 commented 8 years ago

I think we can go a step further to just support object syntax in bind-class and bind-style, so we can remove v-class and v-style. In addition, bind-class can accept an array:

<!-- object for toggling -->
<div bind-class="{ color: true, active: false }"></div>

<!-- array for class list -->
<div bind-class="['ui', 'button', color]"></div>

<!-- plain string bind -->
<div bind-class="classString"></div>
gapipro commented 8 years ago

Wouldn't be nicer to have v-class instead of bind-class with this kind of object syntax support?

<!-- plain string bind -->
<div bind-class="classString"></div>

classString as expression or string?

yyx990803 commented 8 years ago

@gapipro I just find it unnecessary to have v-class and bind-class when the only difference is the format of data they can handle.

classString is an expression. For example vm.classString = 'ui button'.

gapipro commented 8 years ago

Yes having both is unnecessary. I just like having v-class more then bind-class because it is easier to notice when coding html.

yyx990803 commented 8 years ago

@gapipro the idea is you can make any attribute data-bindable just by adding bind- before it. It's similar to v-attr="class: ..." but with better syntax.

gapipro commented 8 years ago

Oh ok. Got it.

HellPat commented 8 years ago

i like it :+1:

mcallan83 commented 8 years ago

Two thumbs up!

holic commented 8 years ago

I like it!

Somewhat related: I find myself always using v-if and never v-show. What is the advantage of v-show over v-if and when are you likely to use one over the other?

(Ultimately wondering if there is no good case for v-show, if it can be deprecated in favor of v-if?)

Mat-Moo commented 8 years ago

V-show shows/hides the element with CSS v-if adds and removes it from the DOM, where possible you should use v-show as it will be faster (think I've got that right)

holic commented 8 years ago

where possible you should use v-show as it will be faster

@Mat-Moo Do you have a source for this fact?

yyx990803 commented 8 years ago

@holic v-show is simple CSS toggling, v-if is true conditional compilation. For example if a component is inside v-if, it will be destroyed/compiled when the v-if is toggled. v-if is also lazy, i.e. If the condition is false on load, it won't do anything. So, when to use which really depends on the use case.

mark-hahn commented 8 years ago

I've had a number of case where v-if didn't work for me and v-show did. I never took the trouble to find out what was going on because I think v-show is cleaner anyway. It doesn't change the dom structure.

On Mon, Aug 31, 2015 at 5:23 PM, Evan You notifications@github.com wrote:

@holic https://github.com/holic v-show is simple CSS toggling, v-if is true conditional compilation. For example if a component is inside v-if, it will be destroyed/compiled when the v-if is toggled. v-if is also lazy, i.e. If the condition is false on load, it won't do anything. So, when to use which really depends on the use case.

— Reply to this email directly or view it on GitHub https://github.com/yyx990803/vue/issues/1173#issuecomment-136534869.

simplesmiler commented 8 years ago

v-if by itself is never faster then v-show, but can improve overall performance of the application by removing dom elements you don't need right now. Things like modals and drop-down menus.

J-F-Liu commented 8 years ago

Can I call a method in binding expression? e.g. <div bind-class="{ active: isActive('cat') }"></div>

Mat-Moo commented 8 years ago

@holic toggling a CSS element between display none/block vs compiling and inserting new dom nodes, think it's pretty obvious :) @mark-hahn ive got an edge case for v-if at the moment that I need to look at once I complete the upgrade to 1alpha. Something along the lines of <my-component v-if="selected!==false" prop-widget="@widgets[selected]"> @simplesmiler for drop down menus? You sure, that to me would be a v-show case, unless it's dynamically generated.

nkovacs commented 8 years ago

Why the separate prop- prefix? Why not just use bind- for properties too? And if there's no bind- prefix, it becomes a literal string.

I'm also torn about losing mustaches. This makes sense, and it would be nice to still be able to do it:

<p class="a b {{c}}" title="More info: {{foo}}">{{bar}}</p>
<my-component foo="foo-{{bar}}">{{baz}}</my-component>

(if bar === 123, the value of foo in my-component here should be the string "foo-123").

But then you have this:

<my-component foo="{{bar}}">{{baz}}</my-component>

This should mean that the value of foo is always a string, and it's always a one-way binding, the same way <input value="{{foo}}" /> works. It actually means bind-foo="bar" (so you can do foo="{{'123'}}" to pass a string and foo="{{123}}" to pass a number), and it would break BC to change that. If it were changed to just string templating, which would be consistent, the difference between this and bind- would be subtle and confusing. It would make sense, but only if you think about it.

Also, taking this to its logical extreme:

<my-component bind-foo="prop{{bar}}">{{baz}}</my-component>

which would mean bind foo to the variable whose name starts with "prop" and ends with the value in bar.

yyx990803 commented 8 years ago

@nkovacs Because attributes and props are different things. bind- means dynamically binding a plain HTML attribute. prop- is specifically for data passing between components. In the original syntax you basically have to "guess" if something is a prop or just a normal attribute.

I'm also considering preserving mustaches for normal attribute bindings, but mustaches inside bind- or prop- will never happen.

nkovacs commented 8 years ago

Well, components are basically custom elements, so I don't really see much of a difference between attributes and properties.

And it would be nice to be able to be able to use mustaches and literal strings in properties too:

<my-component color="green" tooltip="More info: {{foo}}">{{bar}}</my-component >

instead of

<my-component prop-color="'green'" prop-tooltip="'More info: ' + foo">{{bar}}</my-component >

On a side note, wouldn't this also make sense?

<input bind-value="@foo" />

It already works one way. Yes, you need special code to handle the two-way binding, but it looks logical in the template, and it reinforces that properties and attributes are not that different.

yyx990803 commented 8 years ago

@nkovacs that's an idealistic view which makes sense in Polymer, but not in Vue, because Vue components are not custom elements. And even for real elements, attributes and properties are different. It's a bad idea to pretend they are the same.

I've explained in the proposal: the purpose of thebind- and prop- prefix is so that you know what follows is always an expression. It doesn't make sense to have mustaches inside expressions. Mustaches are for string interpolations and should only appear inside plain strings.

Vue templates are not string templates, but real HTML plus binding syntax. And I want to make it explicit.

nkovacs commented 8 years ago

Sorry, I made a mistake in my example. The tooltip property should not have had the prefix.

fullfs commented 8 years ago

Considering new binding syntax, is there any way to bind 2 clicks at once? Right now we sometimes use constructions like v-on="click: methodOne, click: methodTwo". Its useful while extending components.

yyx990803 commented 8 years ago

Sep 2. Thoughts

I'd like to get feedback on one remaining problem of the new syntax: literal directives.

Previously, both reactive and literal directives share the same v- prefix. This is not ideal because when you see v- prefixed directive in the template, you have to remember whether it is literal or not in order to read and understand its value.

Now, with the new syntax, all v- prefixed directives are supposed to be reactive. But we lose the ability to create custom literal directives, which is sometimes actually useful. For example, the v-link directive used by vue-router. Most of the time we want just a literal string for its value, but following the v- = reactivity rule, we'd need to wrap it inside quotes, which is a bit awkward:

<a v-link="'/abc'"></a>

After thinking about it for a while, I start to ask myself: is it really necessary to keep the v- prefix? What if all directives are simply custom attributes? For example, if we register a directive named show, it no longer appears as v-show. Instead, similar to normal attributes, we also use the bind- prefix to indicate reactivity. So the core directives would become:

<!-- view logic -->
<p bind-show="ok"></p>
<p bind-if="!ok"></p>
<p bind-for="item in items"></p>

<!-- two-way binding -->
<input bind-model="val">

Here the bind- indicates the attribute values are expressions. And to simulate a 0.12 literal directive, we simply omit the bind- prefix. Suppose we rename v-link to router-link, we'd use it as follows:

<!-- bound to literal value "/abc" -->
<a router-link="/abc"></a>

<!-- bound to expression -->
<a bind-router-link="'/abc/' + segment"></a>

The downside of this is that we lose the familiar v- prefix, which very explicitly tells us something is a directive. This may also be too much of a conceptual shift from the current API. So if we can find a less disruptive way to solve the literal directive problem, that would be great too.

yyx990803 commented 8 years ago

@fullfs maybe something like on-click="[method1, method2]"? Currently you can do on-click="method1($event), method2($event)" but not very clean

fullfs commented 8 years ago

@yyx990803 on-click="method1($event), method2($event)" is ok. I'd like to have the ability to pass arguments into functions. Can't imagine something likeon-click="[method1($event), method2($event)]"

About Sep 2. Thoughts. Is it just me, or rejecting -v prefix at all is actually the same thing as having it for all Vue-related attributes?

mark-hahn commented 8 years ago

The current "v-" syntax is very readable. Mixing it up with all the "bind-" stuff would throw away useful visual information and make it less readable.

On Wed, Sep 2, 2015 at 9:20 PM, Andrey notifications@github.com wrote:

@yyx990803 https://github.com/yyx990803 on-click="method1($event), method2($event)" is ok. I'd like to have the ability to pass arguments into functions. Can't imagine something likeon-click="[method1($event), method2($event)]"

About Sep 2. Thoughts. Is it just me, or rejecting -v prefix at all is actually the same thing as having it for all Vue-related attributes?

— Reply to this email directly or view it on GitHub https://github.com/yyx990803/vue/issues/1173#issuecomment-137326649.

alchen commented 8 years ago

I also like the v- prefix to immediately recognize that these properties have something to do with Vue.

@yyx990803 I'm in the process of "fixing" my app to work with 1.0.0 and I see now there's a warning for props not declared on the child component. One use case I have will always trigger this warning (if I understood the warning correctly):

I end up with a component looking like this:

          <component
            bind-is="currentFrame"
            prop-one="one"     // used by tab 1
            prop-two="two"     // tab 2
            prop-three="three" // tab 3
          ></component>

What would you advice in this case?

Also, How does transitions work now? I have a plain element with v-if and v-transition with CSS transitions that now fails with: Cannot read property '$options' of undefined. I suspect this may be because the transition is applied to a non-component but I haven't had time to verify.

And, somewhat off-topic, unobservable objects are also giving me headaches. I used to be able to store a moment() variable to display the current time (which I update with a timer every x seconds), but that now throws a warning; the walker goes into the object and stumbles on the Date object inside and complains.


bind-is seem to fail in nested component, but works fine at the top level; simply switching back to is solves the problem and no deprecation warning is displayed.

simplesmiler commented 8 years ago

We have a lot of things (normal html attributes, component props, directives) expressed in the same way (html attributes).

One way to make everything consistent would be:

The downside is that this will be very verbose:

<my-input
  prop-label="Name"
  bind-prop-value="@name"
  bind-v-if="show"
>
</my-input>

This was almost the case in 0.12.12, except for:


Another thing we can go for is using special symbols in attribute names:

<my-input
  prop-label="Name"
  @prop-value="name"
  #v-if="show"
>
</my-input>
simplesmiler commented 8 years ago

@alchen components that you can stick into a certain <component is="..."></component> should probably implement a single interface (read: have the same set of props).

iJackUA commented 8 years ago

In this new approach I like bind- approach - to remove special cases v-attr and v-class that were a little confusing. It makes more consistent dynamic binding to tag attributes.

For a special Vue related directives I would definitely like to see v- prefix - it allows to see "that it is related to Vue for sure!"

Event syntax seems fine for me. Almost equal as for readability.

As for prop- I am not sure. I haven't use them much, but it was looking more familiar without prop- prefix. But I agree that it should accept an expression by default and therefor can't be without any prefix. Maybe to have bind- also ? (To reduce amount of different variations)

But I still have doubts what was looking more clean/clear <a bind-href="'/abc/' + someId"></a> or <a href="/abc/{{someId}}"></a> Mustache way looks nicer, but what about performance? Without Mustache it is better ?

@simplesmiler making everything a literal by default doesn't seems for me a good way - as mostly we use dynamic reactive binding to some VM properties, instead of passing in a plain String values. I think that code will became much more bloated with bind- and bind-v. Special symbols - either not the best way. It makes code a "so alien stuff" from the first look (of a person not familiar enough with Vue)

davidkhess commented 8 years ago

I agree with @fullfs. How about:

• v-on-* – expression based event handlers • v-prop-* – prop expressions • v-bind-* – expression based directives and attributes • v-* – literal directives • * – plain literal attributes having nothing to do with Vue

It's not as clean as it would be nice to have it — but that's likely impossible when trying to cram multiple namespaces into the single existing one of element attributes.

gapipro commented 8 years ago

@davidkhess your suggestion looks quite nice.

yyx990803 commented 8 years ago

Really appreciate the feedback from everyone. Here's an updated proposal:

  1. v- directives (flow control & form handling, same as alpha.2)

    <!-- flow control -->
    <div v-if="ok">
    <div v-for="item in items">
    <div v-show="hi">
    
    <!-- two-way form binding -->
    <input v-model="abc">
  2. on- handlers (same as alpha.2):

    <input on-keyup:enter="abc">
    <form on-submit="handleSubmit">
  3. bind- can also be used for component props. So it can be used like this:

    <!-- component props -->
    <component
     literal="hello"
     bind-dynamic="parentMsg"
     bind-two-way="@something"
     bind-one-time="*something">
    </component>
    
    <!-- normal attributes -->
    <img bind-src="...">
    <a bind-href="...">
    
    <!-- class & style are enhanced to accept objects and arrays -->
    <div bind-class="{ ... }"></div>
    <div bind-class="[ ... ]"></div>
    <div bind-style="{ ... }"></div>
  4. literal directives (add a colon at the end of the directive name to indicate literal):

    <!-- literal (with colon) -->
    <a v-link:="/abc/123">
    
    <!-- dynamic (without colon) -->
    <a v-link="'/abc/' + id">

    This also eliminates the need for a custom directive to declare itself as literal or not - it can simply provide an update function. If it is used as a literal directive, the plain string will be passed into the update function; if it is used dynamically, then the value of the expression will be passed in instead (and call update again when it changes).

    Note: The reason for choosing colon here is because in practice, the only non-alphabetic and easily-typable chars allowed in attributes names are _, -, . and :, and colon looks the most natural here because := is used as assignment operator in many languages.

gapipro commented 8 years ago

@yyx990803 Perfect

kazupon commented 8 years ago

:+1: Looks pretty good !