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

Type ascription #803

Merged
merged 7 commits into from Mar 16, 2015

Conversation

Projects
None yet
@nrc
Copy link
Member

nrc commented Feb 3, 2015

Closes #354

rendered

@nrc nrc referenced this pull request Feb 3, 2015

Closed

Implement type ascription. #21836

@nrc nrc self-assigned this Feb 3, 2015

```
P ::= SP: T | SP
SP ::= var | 'box' SP | ...
```

This comment has been minimized.

@P1start

P1start Feb 3, 2015

Contributor

I think P vs. SP could be clarified here. pat: type is not a valid pattern (e.g., in match) today, and the only thing that resembles that syntax is let’s syntax. Is P supposed to represent what goes in between the let and = in let <P> = <value>;? If so, it should probably be clarified that P is not just a normal pattern.

In type checking, if an expression is matched against a pattern, when matching
a sub-pattern the matching sub-expression must have the ascribed type (again,
this check includes subtyping and implicit coercion). Types in patterns play no
role at runtime.

This comment has been minimized.

@P1start

P1start Feb 3, 2015

Contributor

How does type ascription in patterns interact with let and function declarations? Presumably, let would now just be followed by a pattern (rather than a pattern optionally followed by a colon then a type), and the same for function parameters. Function parameters are required to have their types fully specified, but type ascription complicates this in that fn foo((x: i32, y: i64)) should be valid as well as the current fn foo((x, y): (i32, i64)). Presumably the rule simply needs to be adjusted to something like a pattern in a set of function parameters must have its type determinable without using type inference. That rule would allow some interesting cases that don’t even need type ascription like fn foo(NonGenericStruct(a, b), (), SingleVariantEnum), which may or may not be desirable.

This comment has been minimized.

@nrc

nrc Feb 9, 2015

Author Member

I believe the last example is desirable. I'll update the RFC to clarify this and your previous point.

@sanxiyn

This comment has been minimized.

Copy link
Member

sanxiyn commented Feb 3, 2015

RFC probably should say that this replaces currently limited type ascriptions in let and parameters(both fn and ||), and parameters in fn still must be typed patterns.

// With type ascription.
fn foo(Foo { a: i32, .. }) { ... }
```

This comment has been minimized.

@kennytm

kennytm Feb 3, 2015

Member

What would we get inside foo:

fn foo(Foo { a: Bar, .. }: Foo<Bar>) { ... }
  • A variable named a, or
  • A variable named Bar (the current behavior)?

This comment has been minimized.

@nrc

nrc Feb 9, 2015

Author Member

Good question. I don't think there is a good answer. I think the least worst is to assume that users will prefer the common pattern of using the same name for both the name of the field and the new variable (fn foo(Foo { a, .. }: ... in the current syntax), then assume that a single : in a pattern always denotes a type, i.e., we assume Bar is always a type (this is backwards incompatible, as you allude to). If a user wants to rename the variable, then they'd have to use a : b : _, which is bad. I think the alternative is theoretically nicer - type ascription should be more optional, but less practical, since it is common to reuse the field name.

This comment has been minimized.

@P1start

P1start Feb 9, 2015

Contributor

I would say that it’s probably more common to want to rename the variable than to ascribe the type. After all, we don’t ascribe the type of any struct field patterns today (because we can’t), and that isn’t causing any major problems. The Foo { a, .. } notation is really just shorthand/syntactic sugar for Foo { a: a, .. }, so I feel it should have a lower priority than other more fundamental parts of the syntax. Foo { a: b: _, .. } (explicitly renaming) looks pretty bad and is not an obvious way of resolving the ambiguity, while Foo { a: a: Type } (explicitly type-ascribing) looks OK and is fairly obvious given that the shorthand is just optional sugar.

I think that Foo { a: b, .. } not working would be too surprising to be worth it, and the backwards-incompatibility also just makes matters worse. (Even better in my opinion would be to change struct initialisers to stop overloading :, but that’s already been discussed (in this RFC and elsewhere).)

This comment has been minimized.

@nrc

nrc Feb 9, 2015

Author Member

Yeah, on second thoughts, this makes more sense. Avoiding the backwards incompatibility/code churn is especially desirable. I think I was over-estimating how often type ascription would be used.

This comment has been minimized.

@CloudiDust

CloudiDust Feb 20, 2015

Contributor

While it is more common to want renaming than type ascription, I think Foo {x: x: Foo, y: y: Bar} is still a bit strange, would Foo {.x: Foo, .y: Bar} look better as a sugar? (If we don't change the value binding sigil to =>.)

@oli-obk

This comment has been minimized.

Copy link
Contributor

oli-obk commented Feb 3, 2015

Why not use an identifier and get around the similarity to struct initializers?
explicit conversion is "as". type ascription could be "is" (ok bad idea, typos would happen).
Maybe abuse "be", wouldn't require a new keyword, just sounds rather like bad english when reading?

@blaenk

This comment has been minimized.

Copy link
Contributor

blaenk commented Feb 3, 2015

I think type ascription is great, but I've never liked how everyone's always treated : as the only option for it. I personally find that using : makes everything harder to read. It's harder to pick out quickly and at a glance which parts of the code are type ascriptions, requiring one to scan the context. Personally I would prefer :: from Haskell, but everyone's hellbent on some half-baked attempt to make everything consistent and mirrored.

let z = if ... {
    foo.enumerate().collect() :: Vec<_>
} else {
    ...
};

Or anything else really.

@sfackler

This comment has been minimized.

Copy link
Member

sfackler commented Feb 3, 2015

@blaenk How should this be parsed?

let f = foo::bar::baz;

Is it the path foo::bar::baz, or the path foo::bar with the type ascription baz, or the ident foo with the type ascription bar::baz?

@jsanders

This comment has been minimized.

Copy link

jsanders commented Feb 3, 2015

@blaenk: Do you think you find name: type hard to pick out quickly because it is also used for other things, or just because it has very little "width" to it? I think your proposed syntax is pretty nice, but it would be extremely confusing if the syntax for type ascription were different than the annotations in let bindings and function parameters.

@blaenk

This comment has been minimized.

Copy link
Contributor

blaenk commented Feb 3, 2015

@sfackler fair enough, I completely forgot that paths also use ::. I still think : is difficult to read though :( I think what @oli-obk said are some good ideas, although I think be is reserved for a potential future tail call optimization 'ascription'? I think is would be nice and short, though he raises a good point about easily typod with as. However, I think as is not possible with every single thing (i.e. it'd raise an error to alert the programmer), and in instances when it could be either as or is, either one would be fine?

@jsanders Yeah, very little width is one thing, and also because it's used for explicit typing. When I look at code quickly, at a glance, I have to stop to look at the context to determine if it's an explicit type on a variable, function argument, etc., or if it's a type ascription. It becomes ambiguous to me whether something is a definition or a use of an already defined item. Note that I'm saying it's ambiguous to me, not the compiler.

Also I forgot to mention something that's mentioned in the drawbacks. If we ever --- and I think it's possible given previous discussions --- introduce named arguments, I would much rather have : be used there. The reason I don't think that my aforementioned ambiguity problem would arise there is because you'd have identifier: expression rather than identifier: type, where the latter is already used with explicit typing.

@jsanders

This comment has been minimized.

Copy link

jsanders commented Feb 4, 2015

@blaenk: Interesting, I guess I don't think much about the distinction between definition and use. Changing let x: u32 = 5; to let x = 5: u32 seems completely symmetric to me, but I suppose you could say that in the first case I've assigned the value 5 to a variable with explicit type u32 and in the second case, I've assigned the value of an expression with type u32 to a variable with implicit type. In what ways is that distinction important?

@blaenk

This comment has been minimized.

Copy link
Contributor

blaenk commented Feb 4, 2015

Yeah, I definitely don't think anyone would have much of a problem when it concerns literals, like your example shows.

However, my main concern was for example with function parameters, such as this one from the RFC:

foo(x: &[_], y: &[_]);

From a quick glance, because x and y aren't literals, it's easier IMO to confuse that with a function signature. Here's a possible alternative with is, though I'm not trying to push it in particular.

foo(x is &[_], y is &[_]);

let z = if ... {
    foo.enumerate().collect() is Vec<_>
} else {
    ...
};

Like I said I'm not trying to push is, perhaps there's a better future use for is than this. There's also always a group of people that say that it reads as if it should yield a boolean result, like a check, and may be confusing that way (I think that's just a matter of learning what is does in that case). It's just an example.

But anyways, this is pretty subjective. I'm pretty flexible and I'm sure that I would get used to it without complaining, I just think it's something to think about right now before we go forward.

Especially when we also consider if we would like : for named arguments, which I personally most definitely do. I think the combination of those two factors is enough to at least consider alternatives. If none are found, fair enough. I think the facility of type ascription is more important than the syntax, after all, and I do think we would greatly benefit from having it.

My point is that using an alternative syntax to avoid potential confusion and to allow the possibility of using it for named arguments is insignificant compared to actually having type ascription at all, especially given the other drawback: "Interacts poorly with struct initialisers."

@oli-obk

This comment has been minimized.

Copy link
Contributor

oli-obk commented Feb 4, 2015

since #601 (be -> become) is landing right now, "be" is free again and does not mean tail call anymore.
also, even become makes sense from an english language point of view, and i don't think it would ever collide with tail calls, since "become" would most likely be used like return, and not between an expression and a type

I agree with @blaenk that "is" sounds too much like something returning a boolean due to a runtime-check (or compile-time in case of a generic?)

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Feb 4, 2015

My current feeling:

👍 to the RFC as written. : feels like the right choice for the reasons listed below, and having the precedence match as seems right. Patterns are perhaps a little trickier, but the precedence as written seems right: &x: T, &mut x: T, box x: T. In all those "unary operator" cases, it seems like there are parts of the type already basically implied by the operator, and it's not clear why one would want to repeat those (box patterns are a semi-exception; but they are feature-gated, right?)

👎 to ::, is and become as alternatives. I agree they add a degree of clarity, but : allows us to generalize the existing annotations on patterns in a natural way, and that seems very worthwhile. Also, there is a lot of precedent from other languages. I don't find confusion because a fn def'n and a fn call very likely, given that fn def'ns involve the fn keyword.

@quantheory

This comment has been minimized.

Copy link
Contributor

quantheory commented Feb 4, 2015

I agree with @nikomatsakis, only more so. I think that : is actually clearer than any of the keywords proposed here, simply because of its use in type declarations in Rust already, and because it is sometimes used for definitions (e.g. in glossaries).

x be Foo and x become Foo are both just puzzling at first glance. Using "become" sounds like a cast because it implies a change. Using "be" sounds like a cast because in English it's used for the imperative mood (e.g. dave be Careful looks like the English sentence "Dave, be careful!"). x is Foo might be a little more inherently clear than x: Foo, but it's less consistent with Rust itself, and more confusing for people coming from other languages, like Python, where the is operator tests for association.

(I also don't actually like the idea of using : for named/keyword arguments, so to me that's not a good reason to pick something else. In fact I don't much like that it is used for struct initialization either. I rather wish that we had used =, <-, =>, or some other symbol that implies "association" or "assignment" rather than "definition", though two of those suggestions would technically be ambiguous in the keyword argument context right now.)

@brson

This comment has been minimized.

Copy link
Contributor

brson commented Feb 5, 2015

I feel like this is something that we do not have to do now or any time soon - it's a nice-to-have.

@1fish2

This comment has been minimized.

Copy link

1fish2 commented Feb 5, 2015

I don't think this is a bad feature, but making expressions more complicated has more costs than benefits. (In patterns, the proposal removes some complexity.)

How many let declarations in the library are we itching to combine into longer expressions? Why is that compelling? The Scala Style Guide says:

Ascription is basically just an up-cast performed at compile-time for the sake of the type checker. Its use is not common, but it does happen on occasion.

Benefits

  • foo.enumerate().collect() : Vec<_> is more concise than
    let c: Vec<_> = foo.enumerate().collect(); c

That may be more convenient but overall usability can suffer by making expressions stranger and by encouraging longer expressions.

Sometimes you can just write a literal suffix like 5u32 or expression as type.

Costs

  • Harder to learn the language. One more interpretation of : and one more feature in general.
  • Larger language spec, tutorials, books, etc.
  • Adds complexity to every compiler, language test suite, refactoring editor, program analysis tool, syntax-directed editor, and syntax-coloring web site (like GitHub and Discuss).
  • Opportunity costs for all of these.
  • Interferes with key: value syntax for default function arguments and struct initialization syntax.
@huonw

This comment has been minimized.

Copy link
Member

huonw commented Feb 5, 2015

I'm in favour. I have a library where being able to write:

let foo =
    something.bitcast() : &[u8x16]
        .convert() : &[u8]
        .some_method();

would be useful.

The methods are defined like trait Bitcast<T> { fn bitcast(self) -> T; }, meaning methods themselves aren't generic, so e.g. .bitcast::<&[u8x16]>() doesn't work, but the type annotations are required, since the T type is uninferrable. Being required to separate out those expressions into temporaries is very annoying; it makes sense sometimes, but is annoying at others.

(I imagine this may apply to a generic From trait which has been occasionally discussed, too, and anything with multidispatch.)

On that note, my example is assuming that type ascription works inside method chains like that, which requires having . never being part of a type?

@quantheory

This comment has been minimized.

Copy link
Contributor

quantheory commented Feb 5, 2015

@1fish2: I don't think that this is particularly worse than (or even very different from) the situation with as casts from a parser's perspective. I can probably think of a half dozen somewhat-recent features that are likely to be more troublesome either for users or tools that parse syntax (off the top of my head, UFCS and the .. range literals). That doesn't mean that your point isn't valid, but I feel like this feature is one of the most innocent recent RFCs, as far as adding language complexity is concerned.

My experience with statically typed languages with inference (particularly Haskell is relevant here) is that, even for applications that don't use much type ascription directly, there is a benefit to type ascription for debugging/pedagogy. If you have a type error in code that's using fairly generic functions, but you're not entirely familiar with how the types in a given API work together, you can sometimes use type ascription to figure out which function in the chain is returning something different from what you expect.

That is, you can very quickly iterate with type ascription, in any arbitrary spots in a complex expression, to trigger a type error that's better than the one the compiler gave you at first, and/or to discover which step prevented type inference from resolving an ambiguity. Then you can easily yank the ascription back out of the code if you have a better fix, and it's not needed anymore.

I also think that using type ascription improves readability significantly compared to the alternatives. To be frank, I would much rather have type ascription up front, with some of the weird details of UFCS syntax being the arcane you-should-learn-this-last feature, than to have no type ascription and rely on extra let statements and UFCS for these things. Adding a let is "just" adding verbose boilerplate most of the time (potentially cluttering code with boilerplate declarations of single-use variables that have names like "temp" and "x"), but it can potentially cause some confusion of its own if you accidentally change a lifetime.

Type ascription is one of the simpler features to learn, and I would expect it to be something mentioned pretty early on in most tutorials and books. IMO, the existing workarounds have a much higher cost both for learners and for developers using Rust day-to-day.

@huonw: I like that example. If it doesn't work, there's always this:

let foo =
    ((something.bitcast() : &[u8x16])
        .convert() : &[u8])
        .some_method();

Not so elegant, but possibly less annoying than adding two extra let statements in these cases...

@1fish2

This comment has been minimized.

Copy link

1fish2 commented Feb 5, 2015

Thanks, @quantheory ! That's informative, and those techniques ought to be in tutorials.

Agreed, it's the volume of features that concerns me, not really this particular one.

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Feb 5, 2015

The alternatives mentioned (literal suffixes and as casts) are actually problematic - type ascription would only trigger coercions and type assignments that naturally happen already, while casts are used for potentially overflowing (or truncating, right now) integer conversions, pointer-to-integer/integer-to-pointer and *const T to *mut T.

@brson If we do this now maybe we have a chance to remove literal suffixes from the language? At the very least, using as where coercions work shouldn't be possible, to reduce the meaning of the operator to "potentially dangerous" casts.

Maybe that's undesired, but I am feeling very confident about cleaning up those bits of syntax and semantics.

@oli-obk

This comment has been minimized.

Copy link
Contributor

oli-obk commented Feb 5, 2015

+1 to using type ascription instead of literal suffixes.

@iopq

This comment has been minimized.

Copy link
Contributor

iopq commented Feb 5, 2015

I'd rather have type ascription than literal suffixes, and I would rather change struct notation than lose type ascription.

I didn't care about this feature until I had to work with traits... when writing tests especially you need to have the exact type of basically everything. I had a None in my test that I knew was really a None: Option<String>, but this wasn't legal outside of a let statement. I had to ask on IRC to find out I'd have to write None::<String> which is syntax I'm not familiar with.

Working with closures is another example where I would like to just say

let tuples = [
    ("Fizz", (&|i: i32| i % 3 == 0) : &Fn(_) -> _ ),
    ("Buzz", &|i: i32| i % 5 == 0),
];

but I have to write THIS:

let tuples: [(_, &Fn(_) -> _); 2] = [
    ("Fizz", &|i: i32| i % 3 == 0),
    ("Buzz", &|i: i32| i % 5 == 0),
];

I can't omit even the length of the array, so when I add more stuff to it I have to manually fix it:

let tuples: [(_, &Fn(_) -> _); 3] = [
    ("Fizz", &|i: i32| i % 3 == 0),
    ("Buzz", &|i: i32| i % 5 == 0),
    ("Bazz", &|i: i32| i % 7 == 0),
];

Type ascription is a huge ergonomics deal in current Rust until type inference is much better than what it is now

@glaebhoerl

This comment has been minimized.

Copy link
Contributor

glaebhoerl commented Feb 5, 2015

I'd rather have type ascription than literal suffixes, and I would rather change struct notation than lose type ascription.

Ditto to both. (I'd also rather change struct notation than not change struct notation, but type ascription becoming collateral damage would add injury to insult.)

@quantheory

This comment has been minimized.

Copy link
Contributor

quantheory commented Feb 5, 2015

Do consider the ticking clock for 1.0. If we change the struct syntax now, it's backwards compatible to add type ascription post-1.0. (We could also not change struct initializers at all, at the cost of having to cut out any parts of this RFC that would cause an ambiguity.) If we remove literal suffixes, however, we would want type ascription immediately in order to replace them, which means that it would have to be implemented ASAP.

Once you have type inference and type ascription for unsuffixed literals, literal suffixes are saving very little ergonomically. So I agree that in an ideal world we could just remove them as a redundant language feature. But I think it's up to the core team whether they think that they would be able to implement this RFC quickly enough to break backwards compatibility here.

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Feb 5, 2015

@quantheory this RFC exists because I implemented type ascription on a dare :). Only for expressions, but that seems to be what you're talking about. It would be tinier if it weren't for that weird asm! syntax borrowed from GCC.

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Mar 16, 2015

@nrc I would prefer to cause it to avoid coercion in all ref contexts, personally, though that is I suppose stronger than necessary. This is a bit tricky because, in the case of autoref, we do not know whether something is a ref context until after we have typed the X:T expression -- though thinking on it now, we can certainly do it. The idea would be that we permit coercions but we come back later once we know the full details and trigger a type error if the types do not match exactly. In other words, where the proposed version goes back and triggers an error if any coercion expression appears, the newer version go back and trigger a demand::eqtype. I guess I'd be ok with that, though I imagine it'll take some tweaking to get it right (I envision some corner cases around reborrowing in particular).

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Mar 16, 2015

The core team has decided to approve this RFC. The discussion began with a more wide-reaching proposal that included, among other things, type ascription for patterns, and was gradually simplified into its current form. Notable concerns that were raised and resolved include the following:

  1. Syntactic ambiguity was largely addressed by limiting the : operator to use in expressions, where it is of most use. As is the nature of syntactic questions, there will always be some disagreement about what is the best syntax, but the fact that : has a lot of precedent in Rust as the way you assign types to things gives it a strong "incumbent advantage".
  2. Confusion between implicit coercions (:) and explicit, lossy coercions (as). In particular, there was a danger that people might use as exclusively, thus diluting its advantage as a signal for a lossy coercion. This was addressed through the use of a lint to warn about using as when : (or nothing) would suffice.

There is also a bit of ongoing discussion on how to handle type ascription in a ref context so as to preserve soundness. Although ensuring soundness is important, the precise scenario under discuss seems to be relatively minor and hence can be resolved as we go.

(Note that, as with most RFCs, the intention is to leave the new syntax feature-gated until we've had more time to gain experience with it. In particular, this is not considered a must have for 1.0.)

@nikomatsakis nikomatsakis referenced this pull request Mar 16, 2015

Open

Type ascription (tracking issue for RFC 803) #23416

1 of 6 tasks complete
@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Mar 16, 2015

Tracking issue rust-lang/rust#23416

@nikomatsakis nikomatsakis merged commit e215e59 into rust-lang:master Mar 16, 2015

@nikomatsakis

This comment has been minimized.

nrc added a commit to nrc/rfcs that referenced this pull request Mar 18, 2015

nrc added a commit to nrc/rfcs that referenced this pull request Mar 23, 2015

@ubsan

This comment has been minimized.

Copy link
Contributor

ubsan commented Mar 24, 2015

@nikomatsakis Question: How does this apply to match statements? I believe this would be a very useful case when matching on * pointers, and would completely invalidate #1009, which would be nice.

@nrc

This comment has been minimized.

Copy link
Member Author

nrc commented Mar 24, 2015

@GBGamer what you want (I believe) is type ascription in patterns (a pattern is the general version of the thing to the left of => in a match arm). That was originally part of this RFC, but I took it out to make landing quicker. I still hope to add type ascriptions in patterns at a later date, and that is tracked by #354.

@ubsan

This comment has been minimized.

Copy link
Contributor

ubsan commented Mar 25, 2015

Cool, thanks :)

On Tue, Mar 24, 2015 at 3:28 PM, Nick Cameron notifications@github.com
wrote:

@GBGamer https://github.com/GBGamer what you want (I believe) is type
ascription in patterns (a pattern is the general version of the thing to
the left of => in a match arm). That was originally part of this RFC, but
I took it out to make landing quicker. I still hope to add type ascriptions
in patterns at a later date, and that is tracked by #354
#354.


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

"Unjust laws exist; shall we be content to obey them, or shall we endeavor
to amend them, and obey them until we have succeeded, or shall we
transgress them at once?"
-- Henry David Thoreau

@ticki

This comment has been minimized.

Copy link
Contributor

ticki commented Nov 20, 2015

What's the state of this?

@nagisa

This comment has been minimized.

Copy link
Contributor

nagisa commented Nov 20, 2015

No implementation.
On Nov 20, 2015 12:12 PM, "Ticki" notifications@github.com wrote:

What's the state of this?


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

@petrochenkov

This comment has been minimized.

Copy link
Contributor

petrochenkov commented Nov 20, 2015

Type ascription seems to be cursed - everyone going to rebase rust-lang/rust#21836 disappears immediately.

@vitiral

This comment has been minimized.

Copy link

vitiral commented Aug 17, 2016

I'm not sure what the process is supposed to be for this, but the syntax chosen for this has conflicted with other desireable language features, aka https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/103

Not necessarily that we should implement that feature, but the fact that it conflicts gives credence to how the syntax migh be confusing.

I'm also having difficulty seeing how the (simple) example given in the RFC:

// With type ascription.
let z = if ... {
    foo.enumerate().collect(): Vec<_>
} else {
    ...
};

could not be accomplished with turbofish

// With turbofish
let z = if ... {
    foo.enumerate().collect::Vec<_>()
} else {
    ...
};

Not that turbofish is the greatest syntax ever, but it is in std and serves a purpose. Isn't turbosh nearly orthogonal to this feature, and if so shouldn't this feature be removed?

I am worried about additional syntax appearing in the std language, making things even harder to parse for developers.

@petrochenkov

This comment has been minimized.

Copy link
Contributor

petrochenkov commented Aug 17, 2016

@vitiral
The whole point of the type ascription syntax is symmetry between declarations and expressions:

let a: u8 = 10;
let a = 10: u8;

Changing it would put one more nail in type ascription's coffin.
The ambiguity between type ascription and named arguments can be resolved in favor of named arguments with minimal forward lookup and no breakage on stable.

I'm also having difficulty seeing how the (simple) example given in the RFC ... could not be accomplished with turbofish

There are cases when type hint can't be provided through generic parameters/arguments, e.g.

a.into(): B

Into::into doesn't have generic parameters so you can't write a.into::<B>().

@ubsan

This comment has been minimized.

Copy link
Contributor

ubsan commented Aug 17, 2016

I'm not sure about "coffin"... type ascription doesn't really have a coffin. It's a really great feature, and we're not likely to try and support a special-cased and specialized feature (named parameters) over a very-much wanted and very useful feature (type ascription).

@chriskrycho chriskrycho referenced this pull request Apr 1, 2017

Closed

Document all features #9

18 of 48 tasks complete
@jsgf

This comment has been minimized.

Copy link

jsgf commented Jun 24, 2017

What's the state of this feature?

It seems to me that this would be very useful for futures-oriented programming. Because expressions of composed futures/streams get very complex types, it would be very useful to be able to "pin" parts of an expression to expected types, both to help type inference and to get better error messages. Current mechanisms to do this (let bindings and type-assertion functions) are cumbersome by comparison.

(ping @alexcrichton, @brson as it came up in conversation with them a couple of months ago)

@petrochenkov

This comment has been minimized.

Copy link
Contributor

petrochenkov commented Jun 24, 2017

@jsgf
[meta] The tracking issue is rust-lang/rust#23416, it's better to consolidate the discussion there.

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.