Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch `<>` back to `[]` #148

Closed
wants to merge 11 commits into from

Conversation

Projects
None yet
@thehydroimpulse
Copy link

thehydroimpulse commented Jul 1, 2014

Here we go.

Thoughts?

// Possible syntax for HKTs.
pub trait Monad[M[T]] {
// ...
}

This comment has been minimized.

@lilyball

lilyball Jul 1, 2014

Contributor

How does this bring the ability to have nicer syntax for HKTs? Wouldn't the example be exactly the same when written like this?

pub trait Monad<M<T>> {
    // ...
}

This comment has been minimized.

@thehydroimpulse

thehydroimpulse Jul 1, 2014

Author

That is one syntax proposal for HKTs (following in Scala's footsteps) which is ok (There are better alternatives that focus more on inference). I find [] a lot more composable than <> (i.e., you can nest them without it being cryptic to read).

This comment has been minimized.

@chris-morgan

chris-morgan Jul 1, 2014

Member

I don’t see this as a separate point from the second point.

This comment has been minimized.

@lilyball

lilyball Jul 1, 2014

Contributor

Define "cryptic to read". The nesting properties of [] and <> are identical. You personally may simply have more experience reading nested [] due to being used to Scala. Me, not being a Scala programmer, very rarely encounter nested [] and I find there to be no benefit at all over <>.

This comment has been minimized.

@thehydroimpulse

thehydroimpulse Jul 1, 2014

Author

Yes, imo, [] is much nicer to read than <> without being exposed too much myself (to the [] syntax).

This comment has been minimized.

@chris-morgan

chris-morgan Jul 1, 2014

Member

I think that this claim should be removed—it has no substance apart from the previous claim, is subjective and is not dealing with a concrete situation (HKT is far future).

This comment has been minimized.

@thehydroimpulse

thehydroimpulse Jul 1, 2014

Author

Agreed, fixed!

```rust
fn parse['a, T: Encodable[Encoder['a], IoError]](value: T) {
// ...
}

This comment has been minimized.

@lilyball

lilyball Jul 1, 2014

Contributor

By what criteria are you claiming that this "composes much better"? It's literally the the same number of symbols, arranged in the same fashion, with the same basic properties (balanced pairs of some form of bracket), with the only only difference being one uses square brackets and one uses angle brackets.

You seem to be taking it as a given that what you've stated is true, but without providing any evidence whatsoever, I'm unconvinced that this provides a readability benefit.

This comment has been minimized.

@thehydroimpulse

This comment has been minimized.

@chris-morgan

chris-morgan Jul 1, 2014

Member

What precisely do you mean by composes?

This comment has been minimized.

@thehydroimpulse

thehydroimpulse Jul 1, 2014

Author

Nesting them (i.e., T: Encodable[Encoder['a], IoError] vs T: Encodable<Encoder<'a>, IoError>)

This comment has been minimized.

@lilyball

lilyball Jul 1, 2014

Contributor

@thehydroimpulse Those nest identically.

This comment has been minimized.

@thehydroimpulse

thehydroimpulse Jul 1, 2014

Author

It's not the amount of nesting, it's that [] separates each piece a lot better (imo) than <>, resulting in it being easier to read.

This comment has been minimized.

@chris-morgan

chris-morgan Jul 1, 2014

Member

@thehydroimpulse Then express it that way—for that is different from what people will understand by the other things you’ve said here. Incidentally, I agree with you completely on that claim.

This comment has been minimized.

@thehydroimpulse

thehydroimpulse Jul 1, 2014

Author

@chris-morgan Already in the latest commit.

}
fn main() {
let something = foo[int]();

This comment has been minimized.

@chris-morgan

chris-morgan Jul 1, 2014

Member

This is problematic, colliding with indexing—indexing requires an expression inside the [], specifying generic parameters requires a type or types. Thus I suggest that foo::<int>() is changed to foo::[int]() rather than foo[int](), for now at least.

}
```

4. There's precendence for it. Scala's syntax for generics is awesome. It imposes very little effort when reading and understanding.

This comment has been minimized.

@lilyball

lilyball Jul 1, 2014

Contributor

Not being a Scala programmer, I am unfamiliar with Scala's generics syntax. And again, you are stating without evidence, or without even providing an example of Scala's grammar, that it's more readable.

This comment has been minimized.

@thehydroimpulse

thehydroimpulse Jul 1, 2014

Author

You're right, I'll update it without implying it's a fact.


4. There's precendence for it. Scala's syntax for generics is awesome. It imposes very little effort when reading and understanding.

5. Somewhat related to the first point in that it would bring a consistent syntax for generic everywhere. No more `foo::<>()` that tends to confuse people (not those already aware of the syntax, of course).

This comment has been minimized.

@lilyball

lilyball Jul 1, 2014

Contributor

We can't get rid of foo::<>(). The exact same problem that required us to use that syntax would require us to use foo::[]() with the new syntax. Which is to say, we use ::<> in order to disambiguate the < token between being an operator and being a generic parameter list, and we'd have the exact same issue with [ (as that's also the token that starts a subscript operation).


4. There's precendence for it. Scala's syntax for generics is awesome. It imposes very little effort (I think) when reading and understanding.

6. Because it's consistent and has no ambiguities, one can finally use motions like `%` in Vim (and alternatives in other editors.).

This comment has been minimized.

@lilyball

lilyball Jul 1, 2014

Contributor

I have never had an issue using % in Vim. We do not support the use of < or > as an operator inside of a generic type parameter list, which means there is no problem finding the matching < or > when using %.


Recently there has been a lot of talks on simplifying the syntax. Starting from removing the sigils `@` and `~` and making lifetimes less syntax heavy (through various proposals). I think changing the current generic syntax to `[]` will make it that much better and clearer (I think `[]` is much easier to read).

1. We would remove the current ambiguities surround the current syntax `<>`. That means, we could be able to have:

This comment has been minimized.

@lilyball

lilyball Jul 1, 2014

Contributor

What ambiguities? You haven't described any.

The only ambiguity I know of is the one requiring the use of foo::<int>(), and the change to [] does not resolve that. As @chris-morgan already said, your code example here needs to still be foo::[int]() to be unambiguous.

@chris-morgan

This comment has been minimized.

Copy link
Member

chris-morgan commented Jul 1, 2014

One of the key benefits of using [] rather than <> is that the delimiters are always matching. The use of < and > for comparison operators means that text editors cannot without semantic knowledge treat < and > in generics and type definitions as matching, significantly hindering the modification of such code; in Vim, for example, one cannot in Rust code use the % motion on generics, which is often a real nuisance.

I am surprised by how much easier I find [] to read than <>; the shape of the characters separates the different words more effectively, somehow.

[] are easier to type on most keyboards than <> (lower versus upper).

Using [] may introduce confusion with indexing and array literals.

@lilyball

This comment has been minimized.

Copy link
Contributor

lilyball commented Jul 1, 2014

I don't buy the matching argument. I will readily admit that it's true that [] are always matching, but since we don't support < or > operators inside of type parameter lists, the < and > tokens within a type parameter list are always matching as well. This means that there should be no problem with using % in Vim.

That said, I appear to have broken something, because I swear it used to work for me out of the box, but right now % in Vim is not treating </> as a delimiter. I'm not sure how that would have worked though, as we can't put <:> in 'matchpairs' without causing unexpected beeping when typing an unbalanced >. But we certainly can write our own % operator for the Rust vim file and fix it that way.

@steveklabnik

This comment has been minimized.

Copy link
Member

steveklabnik commented Jul 1, 2014

Big 👎 here. <>s are just as nice looking as [], and have more precident.

}
```

4. There's precendence for it. Scala's syntax for generics is awesome. It imposes very little effort (I think) when reading and understanding.

This comment has been minimized.

@chris-morgan

chris-morgan Jul 1, 2014

Member

After the first sentence, this is pure subjectiveness and not distinct from the earlier points.

What is of note here is this. At the time when Rust changed from [] to <>, there was no known precedent in a C-style language for []-generics: C++ and Java, for example, used <>. Since then, [] has been adopted in at least one fairly popular language, Scala.

This comment has been minimized.

@thehydroimpulse
@thehydroimpulse

This comment has been minimized.

Copy link
Author

thehydroimpulse commented Jul 1, 2014

I think the original issue (from what I heard, don't quote me) to switch was because [] was pretty alien at the time. Now, not so much.


Recently there has been a lot of talks on simplifying the syntax. Starting from removing the sigils `@` and `~` and making lifetimes less syntax heavy (through various proposals). I think changing the current generic syntax to `[]` will make it that much better and clearer (I think `[]` is much easier to read).

1. `[]` is easier to type than `<>`.

This comment has been minimized.

@lilyball

lilyball Jul 1, 2014

Contributor

I disagree. It actually takes less hand movement for me to type <T> on my US English keyboard than for me to type [T].

This comment has been minimized.

@thehydroimpulse

thehydroimpulse Jul 1, 2014

Author

<> needs a shift operator (at least for me), while [] doesn't.

This comment has been minimized.

@chris-morgan

chris-morgan Jul 1, 2014

Member

@thehydroimpulse You should specify on most keyboards; you simply can’t make such assertions without appropriate guard conditions.

@kballard On the standard US English keyboard, [] don’t require the Shift modifier to enter them whereas <> do. The impact of this is reduced for [ as it will normally be followed by an uppercase letter, incidentally, but it won’t for ['a and it won’t for ] unless the last character was also uppercase. This, I presume, is what you are referring to here: for <T> you can just hold the Shift key for all three characters, whereas with [T] you can’t. I accept this case. Still, in most cases I find [] a little easier to type than <>.

This comment has been minimized.

@thehydroimpulse
@cmr

This comment has been minimized.

Copy link
Member

cmr commented Jul 1, 2014

To parse this, when we see a [ after an identifier in an expression, we'll need to defer parsing everything inside until the matching ] until we know the type of the identifier. For example:

foo[bar]

Could be either indexing or taking the value of a generic function, substituting a type parameter, but you won't know.

@thehydroimpulse

This comment has been minimized.

Copy link
Author

thehydroimpulse commented Jul 1, 2014

@cmr Yes there's some ambiguities around arrays with this proposal.


1. `[]` is easier to type than `<>` on *most* keyboards.

2. `[]` delimeters are always matching.

This comment has been minimized.

@chris-morgan

chris-morgan Jul 1, 2014

Member

This needs to be clarified, with reference to the comparison operators < et al. It should be merged in with the sixth point, the practical benefit of this.

This comment has been minimized.

@thehydroimpulse

This is a very easy change to make.

## Downsides

This comment has been minimized.

@chris-morgan

This comment has been minimized.

@thehydroimpulse

# Detailed design

This is a very easy change to make.

This comment has been minimized.

@chris-morgan

chris-morgan Jul 1, 2014

Member

That’s… not much of a detailed design. How about saying something like “in type parameter lists, replace < with [ and > with ].” and giving examples of T<U, …> and f::<T, …>()?

This comment has been minimized.

@thehydroimpulse

This comment has been minimized.

@liigo

liigo Jul 1, 2014

Contributor

The

}
```

3. There's precendence for it. Scala's syntax for generics uses `[]`. At the time when Rust switched form `[]` to `<>` there was no precedence in a C-style language for `[]` generics. That's no longer true.

This comment has been minimized.

@chris-morgan

chris-morgan Jul 1, 2014

Member

s/form/from/

I’d also reword this; perhaps something like “4. At the time when Rust switched from [] to <> there was no precedence in a C-style language for [] generics; this no longer true: Scala is an example of a language that has become fairly popular recently and which uses [] for its generics syntax.”

This comment has been minimized.

@thehydroimpulse

This comment has been minimized.

@liigo

liigo Jul 1, 2014

Contributor

-1, dislike this change!

@chris-morgan

This comment has been minimized.

Copy link
Member

chris-morgan commented Jul 1, 2014

@cmr: foo[uint]() has been removed from the proposal—it is back to being purely a change from <> to [], and thus you would write foo::[uint]().

@lilyball

This comment has been minimized.

Copy link
Contributor

lilyball commented Jul 2, 2014

We can't use () for indexing because we're moving in the direction of having traits that would allow you to make a single value both callable (with ()) and indexable (with []). Which is to say, you could implement a custom closure type that also supports indexing.

@ghost

This comment has been minimized.

Copy link

ghost commented Jul 2, 2014

@kballard () for indexing interests me quite a bit. Can you please elaborate your reasoning why Rust can not apply it? Can you tell an example where there is a need to be able to both call and index a value?

@glaebhoerl

This comment has been minimized.

Copy link
Contributor

glaebhoerl commented Jul 2, 2014

As far as the ugliness of the current type application syntax is concerned, how do people feel about, instead of,

let n = foo::<int>();

writing

let n = foo<type int>();

?

I don't believe type is currently legal in the expression grammar, so I think this should be unambiguous.

It's not shorter, but it's more readable and perhaps less ugly.

@bachm

This comment has been minimized.

Copy link

bachm commented Jul 2, 2014

@glaebhoerl I don't like foo::<int>() because it's an exception to the usual way to do things. This is true for foo<type int>() as well.

@simias

This comment has been minimized.

Copy link

simias commented Jul 2, 2014

@glaebhoerl how would that scale for more complex declarations? Do you put type in front of each parameter? What about nesting?

Also rust might end up adding stuff like constant integer parameters and things like that, "type" wouldn't fit those semantically. What would you do with lifetime parameters? I guess you could say there're a type but that's stretching it a bit IMO.

I don't think this solves anything really, I don't like the ::< "hack" but I like <type> even less...

@bachm

This comment has been minimized.

Copy link

bachm commented Jul 2, 2014

Foo::<int>::f() is also something I dislike. Learning the subtleties of type parameter definitions took me way longer than it should have, and I was already used to C++ syntax. In the long run it's not a big deal, but it feels like poor design.

@glaebhoerl

This comment has been minimized.

Copy link
Contributor

glaebhoerl commented Jul 2, 2014

I never implied that it's perfect, only that it might suck less.

@simias I was thinking the rule would be that if providing a kind annotation (type, static, trait, maybe ') on the first argument makes it syntactically unambiguous, you can omit the ::, but :: would also remain an option. This presupposes a system for kind annotations which we don't have yet, which is why I didn't want to get into it.

@adrientetar

This comment has been minimized.

Copy link

adrientetar commented Jul 2, 2014

:: isn't ugly imo, short and concise and implies a hierarchy just like paths: out of Foo, take the code path for ints.

@simias

This comment has been minimized.

Copy link

simias commented Jul 2, 2014

@adrientetar that's more of a rationalization really. I mean, you can think about it that way but to me :: implies scoping.

But anyway, this is off topic since this proposal still requires :: for disambiguation.

@lilyball

This comment has been minimized.

Copy link
Contributor

lilyball commented Jul 2, 2014

@almale RFC 34 defines traits that can be used for implementing the indexing operator on arbitrary types (we actually already have an existing trait for this, but it's badly-designed and nobody uses it).

RFC PR #114 provides unboxed closures by adding traits to represent function calling. This allows arbitrary types to be callable (as foo()).

Implementing both traits on the same type allows a value of that type to be both indexable and callable. This requires that the indexing and calling operators be syntactically distinct, which means () cannot be used for indexing.

@lilyball

This comment has been minimized.

Copy link
Contributor

lilyball commented Jul 2, 2014

@almale I don't know what a real-life example of such a type will be, but the fact remains that our traits allow for it, and therefore () cannot be used for both indexing and calling. We have no way to express a restriction that a type may be indexable or may be callable but not both.

Furthermore, you cannot resolve that by getting rid of indexing in favor of using calling as the indexing operator, because that doesn't support the distinction between immutable and mutable indexing, or the ability to assign to an index. Note that while the callable traits have variants for mutable and immutable, one type is not allowed to implement both (or more accurately, a() cannot be used as sugar for the trait method if more than one of the traits are implemented on the value).

@liigo

This comment has been minimized.

Copy link
Contributor

liigo commented Jul 2, 2014

C uses [] for index arrary. I don't think there is enough reasons to change
this.
2014年7月2日 下午3:29于 "Almale" notifications@github.com写道:

@kballard https://github.com/kballard () for indexing interests me
quite a bit. Can you please elaborate your reasoning why Rust can not apply
it? Can you tell an example where there is a need to be able to both call
and index a value?


Reply to this email directly or view it on GitHub
#148 (comment).

@boggle

This comment has been minimized.

Copy link

boggle commented Jul 3, 2014

Hi,

could you explain the use case for this? I can't see it. While scala
allows that combination I've never used it in practice. So I would be
quite natural for me to not allow both or rather treat indexing as a
special case of callability and only allow implementing one callability
signature trait per target type. Under this rule, [] works awesomely for
types.

Stefan

Kevin Ballard mailto:notifications@github.com
2. Juli 2014 21:59

@almale https://github.com/Almale RFC 34
https://github.com/rust-lang/rfcs/blob/master/active/0034-index-traits.md
defines traits that can be used for implementing the indexing operator
on arbitrary types (we actually already have an existing trait for
this, but it's badly-designed and nobody uses it).

RFC PR #114 #114 provides
unboxed closures by adding traits to represent function calling. This
allows arbitrary types to be callable (as |foo()|).

Implementing both traits on the same type allows a value of that type
to be both indexable and callable. This requires that the indexing and
calling operators be syntactically distinct, which means |()| cannot
be used for indexing.


Reply to this email directly or view it on GitHub
#148 (comment).

@lexspoon

This comment has been minimized.

Copy link

lexspoon commented Jul 3, 2014

Interestingly, RFC #34 and RFC PR #114 are quite similar to how Scala approaches these problems. One difference is that Scala doesn't require using any particular trait; a type just defines methods of the appropriate name if it wants to use () syntax. Another difference is that Rust uses different identifiers for calling (call, call_share, call_once) and for indexing (index, index_mut). Scala uses the the same identifiers in both cases (apply, update).

I would think, as @boggle suggests, it's up to you whether you want to have objects that are callable and indexable with a different meaning for each one. If that's more of an accident than an actual goal, then couldn't you just use the same set of names for both cases? In rvalue position, expand to (call, call_share, call_once). In lvalue position, it could be (call_mut, call_share_mut, call_once_mut). This is a syntactic transformation that happens before type checking.

Not to say that it's right because Scala does it, or even that it's right at all for Rust. The two languages run into similar challenges due to both trying to bring functional programming to mainstream ecosystems, so I thought I'd share.

@DAddYE

This comment has been minimized.

Copy link

DAddYE commented Jul 22, 2014

In merit to this issue see this: http://www.reddit.com/r/rust/comments/2bbeqe/it_started_out_with_great_enthusiasm_but_ended_up/

We had a small conversation here about one statement from the author: http://www.reddit.com/r/rust/comments/2bbeqe/it_started_out_with_great_enthusiasm_but_ended_up/cj3v5x6

Anyway, I'm one of them that wish we could switch back to [, both I think are better suited and easy to parse mentally.

I don't see that much the point that of c++, I think is something can be mastered within few minutes. Instead I see it problematic for a beginner mentally recognize:

impl<T: Add<T, T>> Add<Vec2<T>, Vec2<T>> for Vec2<T>

@flying-sheep

This comment has been minimized.

Copy link

flying-sheep commented Jul 22, 2014

I really think readability should beat familiarity.

Your example is a good one, as it's very jarring to mentally parse, because
most fonts render <> even smaller than “o” (floating above the baseline),
while they would render (){}[] with full height or even more (as low as “g”
and higher than “L”)

There are angled brackets in Unicode, but (understandably) we don't want to
require the user to be able to type them. So braces, brackets, and
parentheses should be the only enclosing characters in this language that
only has ASCII.

The characters <> really only serve as operators, not fake brackets.

@lilyball

This comment has been minimized.

Copy link
Contributor

lilyball commented Jul 22, 2014

I must admit to being more sympathetic now to the "it looks nicer" argument for [] than I was initially. I still think that's really the only valid argument (all the other ones have been addressed already). I don't know if a purely subjective "nicer" look is worth the unfamiliarity, but I am willing to be convinced. I do worry, as @chris-morgan pointed out initially, that there is a potential confusion with array literals and indexing, but I don't know if that will turn out to be an issue in practice.

@DAddYE

This comment has been minimized.

Copy link

DAddYE commented Jul 22, 2014

@kballard regarding that, I'll quote JouMaSePLoS:

That's a weak argument: () denotes both function application and grouping, and yet no-one ever complains about that. It turns out we're all good at contextual parsing, and I bet that if Rust changed generic syntax to use [] you'd get used to it within a few days.

What we're not good at it, objectively, is inferring nesting. In fact with human language we're notoriously bad at it, and no natural utterances have more than a couple levels of nesting. We need artificial assistance to deal with nesting, and [] is just visually objectively better for deep nesting owing to the height and boxlike nature of the brackets.

Anecdotal data: Mathematica/Wolfram Language uses [] for function application, and () only for grouping. And I now much prefer that convention to everything else -- after you are used to it, [] is hands down the most 'visually parseable' delimiter.

Also, as others pointed out, scala use []: http://www.scala-lang.org/old/node/113
However they use () for index, which isn't that bad if you consider that now we can't slice (IIRC) like my_array[1:2], but we must do my_array.slice(1,2) so, my_array.slice(1) or my_array(1) doesn't look that odd.

However, keep in mind that a language syntax last 20+ years, so I really hope we couldn't carry for 40 years the operator >.

@lilyball

This comment has been minimized.

Copy link
Contributor

lilyball commented Jul 22, 2014

@DAddYE

That's a weak argument: () denotes both function application and grouping, and yet no-one ever complains about that.

That's quite a good point. Though I don't agree with the implication of the latter half of the comment that [] is a better function application operator than ().

@glaebhoerl

This comment has been minimized.

Copy link
Contributor

glaebhoerl commented Jul 22, 2014

I must admit to being more sympathetic now to the "it looks nicer" argument for [] than I was initially. [...] I do worry, as @chris-morgan pointed out initially, that there is a potential confusion with array literals and indexing, but I don't know if that will turn out to be an issue in practice.

I was very confused when I first saw Scala code using [] for generics. I hadn't encountered that choice of syntax before, and it was only much later that I learned what it meant.

Once again, I think () has all the benefit of [] in terms of readability, minus the drawback of semantic confusion.

Parentheses are in fact the most intuitively correct option, as generic types, or types parameterized over types, in a very precise sense are like functions, or values parameterized over values. (Or not even "like": they are functions at the type level. More specifically, they're the same thing on the type level as enum variants are on the value level. General type functions, or associated types, are the precise analogy for general value-level functions, of which "normal" generic types are a specific case in the same way that enum variant construction is of function calls.)

It's not by accident that Haskell shares the same syntax for function calls, data construction (enum variants), and type construction (generics).

(As a side note: I think we could then use foo@(T1, T2, ...) in place of foo::<T1, T2, ...> for type application at the value level. I think the "at" sense of @ is more appropriate than the "in" of ::. But it looks stupid with angle brackets.)

@lilyball

This comment has been minimized.

Copy link
Contributor

lilyball commented Jul 22, 2014

@glaebhoerl We can't use (). We already use those in type constructors. Some::(init)(3i) is just too confusing.

@o11c

This comment has been minimized.

Copy link
Contributor

o11c commented Jul 22, 2014

In a language that had made different fundamental choices about inference and overloading, () could work, but [] works as it is.

It's not considered a bad thing in any language that supports operator overloading that it's possible to overload both 'function call' and 'index' operators depending on what your intention is. And even though maps are functions, templates are still more like maps than they are like other functions.

@glaebhoerl

This comment has been minimized.

Copy link
Contributor

glaebhoerl commented Jul 22, 2014

We can't use (). We already use those in type constructors. Some::(int)(3i) is just too confusing.

"Can't" is a strong word. D does it. (They use ! to distinguish type argument lists from value-level ones; current Rust uses ::; in my previous comment I suggested @.)

I think it's much less bizarre than the clash of [] with indexing.

@DAddYE

This comment has been minimized.

Copy link

DAddYE commented Jul 22, 2014

IMHO both [ and ( are fine. At this point even if this issue is closed is a call of the @rust-lang/team. @thehydroimpulse do you think it's worth reopening this?

@thehydroimpulse thehydroimpulse restored the thehydroimpulse:type branch Jul 29, 2014

@thehydroimpulse

This comment has been minimized.

Copy link
Author

thehydroimpulse commented Jul 29, 2014

@DAddYE Forgot to reply. I think a member of the core team should way in before this is reopened. I don't want to continue a needless bike shed for the sake of it with a low-chance it's going to be taken seriously.

@thehydroimpulse thehydroimpulse deleted the thehydroimpulse:type branch Jul 30, 2014

wycats pushed a commit to wycats/rust-rfcs that referenced this pull request Mar 5, 2019

Merge pull request rust-lang#148 from emberjs/rwjblue-patch-1
Update and rename 0000-isHtmlSafe.md to 0139-isHtmlSafe.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.