Stream: t-lang

Topic: Design meeting: try, oh my!


nikomatsakis (May 04 2020 at 16:03, on Zulip):

Happening now...

nikomatsakis (May 04 2020 at 16:04, on Zulip):

paper document

nikomatsakis (May 04 2020 at 16:06, on Zulip):

@Josh Triplett :point_up:

Lokathor (May 04 2020 at 16:12, on Zulip):

It seems to be a different Zoom link from the triage meeting Zoom link.

cuviper (May 04 2020 at 16:55, on Zulip):

I've added a couple comments, but I'm not on the call -- sorry if that's distracting

nikomatsakis (May 04 2020 at 17:02, on Zulip):

I appreciate folks adding comments, I like to read them over later

pnkfelix (May 04 2020 at 17:02, on Zulip):

so I wasn't able to follow every conversation because (perhaps ironically) I was trying to continue taking notes at the top

nikomatsakis (May 04 2020 at 17:02, on Zulip):

heh :)

pnkfelix (May 04 2020 at 17:02, on Zulip):

but I did have one Question

nikomatsakis (May 04 2020 at 17:03, on Zulip):

I was wondering how you fared with that...

pnkfelix (May 04 2020 at 17:03, on Zulip):

did josh respond to niko's statement that this isn't all that dissimilar from exceptions?

pnkfelix (May 04 2020 at 17:04, on Zulip):

I would like to better understand that. I do understand the notion that we want to avoid association with the expensive exceptions as implemented elsewhere (namely those that capture stack trace)

pnkfelix (May 04 2020 at 17:04, on Zulip):

and if that's the heart of josh's concern, then I grok that

nikomatsakis (May 04 2020 at 17:04, on Zulip):

"manually propagated exceptions"

Josh Triplett (May 04 2020 at 17:04, on Zulip):

pnkfelix said:

did josh respond to niko's statement that this isn't all that dissimilar from exceptions?

I didn't respond to that in the meeting. We were short on time, and I didn't want to continue poking at what seemed like the primary point of dispute rather than trying to determine where there was common ground.

nikomatsakis (May 04 2020 at 17:04, on Zulip):

I had a meta question on this topic I wanted to raise

nikomatsakis (May 04 2020 at 17:04, on Zulip):

which is .. what do we see as the most fruitful way to resolve this :)

nikomatsakis (May 04 2020 at 17:05, on Zulip):

I can see a few options

nikomatsakis (May 04 2020 at 17:05, on Zulip):

there's aways the option of just long and detailed conversation, of course,

nikomatsakis (May 04 2020 at 17:05, on Zulip):

but I'm also wondering about things like:

Josh Triplett (May 04 2020 at 17:05, on Zulip):

@nikomatsakis I think there's value in having some discussions, and then doing some writing in shared documents attempting to jointly understand each others' values and work towards them.

nikomatsakis (May 04 2020 at 17:05, on Zulip):
nikomatsakis (May 04 2020 at 17:06, on Zulip):
nikomatsakis (May 04 2020 at 17:07, on Zulip):

But maybe indeed spending some time drilling more into the motivation of around avoiding connotations (or embracing them) is the obvious first step.

Josh Triplett (May 04 2020 at 17:07, on Zulip):

(I'm going to be in other meetings for a couple of hours, so I'm not going to be able to participate at high bandwidth during that time.)

nikomatsakis (May 04 2020 at 17:08, on Zulip):

my other meta comment is

pnkfelix (May 04 2020 at 17:08, on Zulip):

(i'll just mention that the main reason I suggested signal as the keyword was because that as CLU's keyword for exceptions, and CLU, if i recall correctly, had very cheap exceptions.)

nikomatsakis (May 04 2020 at 17:08, on Zulip):

and I guess my last meta point

Yoshua Wuyts (May 04 2020 at 17:10, on Zulip):

At the end of the call there was a question of: "Which use cases would we like to enable?" -- I wrote a quick overview for how I would see try / Ok-wrapping interact with Tide: https://gist.github.com/yoshuawuyts/3a1639767862704541d166c0de476eaf

Yoshua Wuyts (May 04 2020 at 17:14, on Zulip):

(hope this is the kind of example the lang team was looking for)

nikomatsakis (May 04 2020 at 17:19, on Zulip):

ooh, thanks

nikomatsakis (May 04 2020 at 17:20, on Zulip):

@pnkfelix btw, I think the argument about exceptions is not so much about their perceived runtime cost (although that is no doubt a facet for many people) but also that there is a kind of "zeitgeist" against them. @Taylor Cramer wrote up something quite similar in the comments in the dropbox. So just having exception-like keywords in the language may mislead those who are not well informed on the details. A clear story like "Rust does not have exceptions" is maybe a better selling point for such folks than a muddy story like "Rust has exceptions done right".

nikomatsakis (May 04 2020 at 17:21, on Zulip):

(That said, I personally still favor the exception related terminology, or at least I don't feel I've seen a convincing set of alternative terminology. I think that "X done right" is basically Rust's whole story, in any case.)

pnkfelix (May 04 2020 at 17:21, on Zulip):

I guess I'll have to review how the "Rust has no GC" vs "Rust has a static GC" selling points were handled.

nikomatsakis (May 04 2020 at 17:22, on Zulip):

yeah, it had a similar ring

nikomatsakis (May 04 2020 at 17:22, on Zulip):

I mean I think if we'd ever successfully adding tracing support etc

nikomatsakis (May 04 2020 at 17:22, on Zulip):

we'd be facing similar questions

nikomatsakis (May 04 2020 at 17:22, on Zulip):

certainly the concerns were raised

pnkfelix (May 04 2020 at 17:22, on Zulip):

right. And I want to better understand which works better fo which communities

pnkfelix (May 04 2020 at 17:23, on Zulip):

right now there are some communities that say they won't adopt Rust because it has no GC

pnkfelix (May 04 2020 at 17:23, on Zulip):

but I don't know if that's a PR issue

pnkfelix (May 04 2020 at 17:23, on Zulip):

Or a true "lack of expressiveness" one

pnkfelix (May 04 2020 at 17:23, on Zulip):

maybe I should say "individuals" rather than "communities"

nikomatsakis (May 04 2020 at 17:34, on Zulip):

Yoshua Wuyts said:

At the end of the call there was a question of: "Which use cases would we like to enable?" -- I wrote a quick overview for how I would see try / Ok-wrapping interact with Tide: https://gist.github.com/yoshuawuyts/3a1639767862704541d166c0de476eaf

This is nice, @Yoshua Wuyts, thanks. I'm pondering this example async |_| try { .. }. One of the things I've wondered is if we want to support something like try fn foo() or, perhaps instead,

fn foo() -> Result<...> = try {
    ..
}

I was struck by some of the parallels there.

I'm curious though about the get signature on app.at().get() -- how constrained is it? In particular, will it hit type inference limitations?

nikomatsakis (May 04 2020 at 17:39, on Zulip):

So I summarized my main takeaways from the meeting -- I'd be curious if anyone sees anything to add there?

nikomatsakis (May 04 2020 at 17:43, on Zulip):

One thing I'm particularly curious about is whether it would make sense to "just stabilize Try trait as is". I'm not the world's biggest fan, but given that we're at least somewhat locked in here... I guess @scottmcm I'd like to get your thoughts on that at some point. (And/or review a proposed alternative design.)

Lokathor (May 04 2020 at 17:45, on Zulip):

Can the Try trait be stabilized as is separately from try-blocks and ok-wrapping mechancis?

Josh Triplett (May 04 2020 at 17:46, on Zulip):

If stabilizing the trait as-is means we would always have to write annotations on try, I'd want to try to find alternatives first that would make that not always required.

Jane Lusby (May 04 2020 at 17:47, on Zulip):

awe lame, i missed the meeting

Josh Triplett (May 04 2020 at 17:47, on Zulip):

@Jane Lusby I would have loved to have had your input, personally.

Jane Lusby (May 04 2020 at 17:47, on Zulip):

:sob:

nikomatsakis (May 04 2020 at 17:48, on Zulip):

Josh Triplett said:

If stabilizing the trait as-is means we would always have to write annotations on try, I'd want to try to find alternatives first that would make that not always required.

I think it's not that simple, but there is some connection. To some extent it's "too late", as we already have a non-unique relationship where Result can be converted to non-Result things.

Jane Lusby (May 04 2020 at 17:48, on Zulip):

well, ill check out the recording once its available and write down my thoughts

Josh Triplett (May 04 2020 at 17:48, on Zulip):

This is true; that does constrain our possible solutions.

nikomatsakis (May 04 2020 at 17:48, on Zulip):

nikomatsakis said:

So I summarized my main takeaways from the meeting -- I'd be curious if anyone sees anything to add there?

@Jane Lusby see also :point_up: :)

Josh Triplett (May 04 2020 at 17:49, on Zulip):

@nikomatsakis I think there's enough value in avoiding annotations that I'd be interested in the family of solutions involving changing the desugar in an edition, if that means that code in a new edition doesn't need as many annotations.

Josh Triplett (May 04 2020 at 17:50, on Zulip):

I do think that shouldn't be done lightly though.

nikomatsakis (May 04 2020 at 17:51, on Zulip):

I guess I don't think it's the most reliable sol'n to that problem

Josh Triplett (May 04 2020 at 17:56, on Zulip):

/me thinks about use cases for which omitting the annotation seems likely to be relevant.

Taylor Cramer (May 04 2020 at 18:06, on Zulip):

Personally I'd push for solutions which make writing the type annotation something that is easy and elegant and is nearly always done

Taylor Cramer (May 04 2020 at 18:06, on Zulip):

or always done

Taylor Cramer (May 04 2020 at 18:06, on Zulip):

since otherwise there will be a cliff in user experiences when you fall of the "happy path" where inference used to work

Taylor Cramer (May 04 2020 at 18:07, on Zulip):

(of course, you could use that to argue against inference in general, but I think the tradeoffs balance differently here)

Josh Triplett (May 04 2020 at 18:19, on Zulip):

One common use case where I'd like inference to work:
try { ... }.with_context(|| common_context())?;

Josh Triplett (May 04 2020 at 18:19, on Zulip):

It'd be nice to not have to tell rustc what type the try is.

Josh Triplett (May 04 2020 at 18:19, on Zulip):

I absolutely understand that'll be hard.

Josh Triplett (May 04 2020 at 18:20, on Zulip):

Another use case (which might be better handled other ways, but it's nonetheless not uncommon):
let result = try { ... }; cleanup(); let value = result?; ...

Taylor Cramer (May 04 2020 at 18:20, on Zulip):

try Result<_, Error> { ... }.with_context(|| common_context())?; seems pretty close

Josh Triplett (May 04 2020 at 18:20, on Zulip):

(That might be better handled by having some type whose Drop calls cleanup(), but still...)

Taylor Cramer (May 04 2020 at 18:20, on Zulip):

try { ... }:Result<_, Error>.with_context(|| common_context())?;

Josh Triplett (May 04 2020 at 18:21, on Zulip):

Taylor Cramer said:

try Result<_, Error> { ... }.with_context(|| common_context())?; seems pretty close

For values of "pretty close" that still feel really painfully verbose.

Taylor Cramer (May 04 2020 at 18:21, on Zulip):

also works and aligns with the rest of our type ascription story (well, what we have of one anyways)

Josh Triplett (May 04 2020 at 18:21, on Zulip):

At that point, I'd probably try to write some helper function that forces the type just so I don't have to repeat the type ascription everywhere.

Josh Triplett (May 04 2020 at 18:21, on Zulip):

Or a wrapper around try.

Josh Triplett (May 04 2020 at 18:22, on Zulip):

try_anyhow!{ ... }, translating to try : anyhow::Result<_> { ... } or similar.

Josh Triplett (May 04 2020 at 18:22, on Zulip):

I'd like to not have to immediately wrap try in a macro to make it feel usable without repeating myself everywhere.

Taylor Cramer (May 04 2020 at 18:22, on Zulip):

yeah, that seems plausible and I'd imagine things like that would exist in much the same way that type Result<T> = Result<T, MyError>; is common

Taylor Cramer (May 04 2020 at 18:23, on Zulip):

(though I personally dislike that pattern of reusing the name Result)

Yoshua Wuyts (May 04 2020 at 18:23, on Zulip):

nikomatsakis said:

I'm curious though about the get signature on app.at().get() -- how constrained is it? In particular, will it hit type inference limitations?

Good question! I don't know enough about the implementation to gauge whether it will hit limitations, but from a usability perspective I'd argue that it should be a design goal to enable inference to work here.

Josh Triplett (May 04 2020 at 18:23, on Zulip):

Taylor Cramer said:

(though I personally dislike that pattern of reusing the name Result)

I find anyhow::Result an exception to the usual reasons to dislike that pattern, because it's just a type alias that adds a default for the second type parameter, but you can still write the second type parameter. So if you use anyhow::Result nothing goes wrong with code that used Result<T, E>.

Yoshua Wuyts (May 04 2020 at 18:24, on Zulip):

(deleted)

Josh Triplett (May 04 2020 at 18:24, on Zulip):

Though I still tend to write anyhow::Result without importing it.

Yoshua Wuyts (May 04 2020 at 18:35, on Zulip):

nikomatsakis said:

This is nice, Yoshua Wuyts, thanks. I'm pondering this example async |_| try { .. }. One of the things I've wondered is if we want to support something like try fn foo() or, perhaps instead,

fn foo() -> Result<...> = try {
    ..
}

Ah yes definitely! I wasn't sure if that'd be off-topic here since the meeting didn't quite touch on it -- but it seems to me that stabilizing try would also create some obvious tension with proposals forthrows (fn foo() -> throws io::Error {}). I believe towards the end of the meeting it was brought up we should probably consider how all of these pieces could end up working together, which seems like a good idea.

Josh Triplett (May 04 2020 at 18:37, on Zulip):

@Yoshua Wuyts As far as I know, I don't think try fn/throws would be directly affected, positively or negatively, by stabilizing try, except insofar as doing so allows alternatives like = try {}.

nikomatsakis (May 04 2020 at 18:39, on Zulip):

I was pondering how much alignment is required to move forward with try. There is something .. strange to me about having an "ok-wrapping" form through try, but nothing at the "fn level".

nikomatsakis (May 04 2020 at 18:40, on Zulip):

I guess it's that I think of the idea of ? as being aligned to fn scope, and try as being a way to narrow that scope, so it's sort of surprising to me that it has secondary effects.

Josh Triplett (May 04 2020 at 18:40, on Zulip):

I do think there's value in having a function-level Ok-wrapping try, yes.

Josh Triplett (May 04 2020 at 18:41, on Zulip):

As far as I can tell, the primary point of dispute is "what does the type signature look like". :)

nikomatsakis (May 04 2020 at 18:41, on Zulip):

I guess there is also an interaction, and perhaps this was what @Yoshua Wuyts was getting at, between

try: Result<_, _> { .. }

notation and something like

fn foo() -> Result<_, _> { .. }

In other words, if we have built-in type annotation on try, and we added try fn, I would expect them to work analogously.

nikomatsakis (May 04 2020 at 18:41, on Zulip):

/me thinks

Josh Triplett (May 04 2020 at 18:41, on Zulip):

...that's a really interesting argument.

Josh Triplett (May 04 2020 at 18:42, on Zulip):

/me thinks as well.

Yoshua Wuyts (May 04 2020 at 18:42, on Zulip):

heh, yeah that's what I was trying to get at (:

Josh Triplett (May 04 2020 at 18:42, on Zulip):

/me tries to reconcile his "I don't want to write the type annotations on try" with "I very much want to see Result on fn".

Josh Triplett (May 04 2020 at 18:42, on Zulip):

I feel like that's a consistent position, but it's worth thinking about.

Josh Triplett (May 04 2020 at 18:42, on Zulip):

It's generally consistent with "I want type annotations at the function level, but I don't mind inference within functions".

nikomatsakis (May 04 2020 at 18:43, on Zulip):

I think there is another point to consider

nikomatsakis (May 04 2020 at 18:43, on Zulip):
async fn foo() -> u32 { }

made the precedent (for strong reasons) that the return type is the "inner type" that the fn body sees

nikomatsakis (May 04 2020 at 18:43, on Zulip):

and the "outer type" that the outside world sees

Josh Triplett (May 04 2020 at 18:44, on Zulip):

/me would actually like to better understand those "strong reasons".

nikomatsakis (May 04 2020 at 18:44, on Zulip):

(this is contrast to e.g. C#, which iirc writes

async void foo() -> Task<u32>
nikomatsakis (May 04 2020 at 18:44, on Zulip):

There are a bunch of reasons, but one very strong one is that the actual type you want is very complex to type in the case of async fn :) -- because of the rules around lifetime capture and impl Future types.

Josh Triplett (May 04 2020 at 18:45, on Zulip):

As in, substantially more complex than impl Future<u32>?

Josh Triplett (May 04 2020 at 18:45, on Zulip):

(Leaving aside the whole Output= problem, which seems like a quirk of how Future is designed.)

Yoshua Wuyts (May 04 2020 at 18:47, on Zulip):

Something that I haven't seen brought up in discussions much, but still think is worth discussing is the option of making fn foo() throws {} use Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> as its return type

Yoshua Wuyts (May 04 2020 at 18:48, on Zulip):

Which leans in even further into the error type not being explicit, but would be more comparable erasing Future in the return signature

Yoshua Wuyts (May 04 2020 at 18:50, on Zulip):

(the rule being: if an error type is not specified we fall back to a generic "dyn Box Error type", whichever shape that might be)

Jane Lusby (May 04 2020 at 18:53, on Zulip):

seems like using a catch all error type thats default recommended is a hazard

Jane Lusby (May 04 2020 at 18:53, on Zulip):

with specialization it should be able to start impling Error itself I assume

Jane Lusby (May 04 2020 at 18:53, on Zulip):

but for right now Box<dyn Error> doesn't impl error and cant be conveniently wrapped by other types that impl From<E: Error>

Jane Lusby (May 04 2020 at 18:55, on Zulip):

nikomatsakis said:

I guess there is also an interaction, and perhaps this was what Yoshua Wuyts was getting at, between

try: Result<_, _> { .. }

notation and something like

fn foo() -> Result<_, _> { .. }

In other words, if we have built-in type annotation on try, and we added try fn, I would expect them to work analogously.

I feel like the type annotations on try blocks here have a lot in common with the theoretical syntax for try fns

Jane Lusby (May 04 2020 at 18:55, on Zulip):

in that it could be ```rust

Jane Lusby (May 04 2020 at 18:56, on Zulip):
try -> u32 throws Error { .. }
Jane Lusby (May 04 2020 at 18:56, on Zulip):

you start running into similar issues about "resultness"

Yoshua Wuyts (May 04 2020 at 18:57, on Zulip):

@Jane Lusby not sure I follow that last example? is that both try and throws on the same function?

Yoshua Wuyts (May 04 2020 at 18:57, on Zulip):

or wait, on the same block?

Jane Lusby (May 04 2020 at 18:57, on Zulip):

yea

Jane Lusby (May 04 2020 at 18:57, on Zulip):

in that you have a desire to annotate different levels of the type with try blocks and try fns

Jane Lusby (May 04 2020 at 18:58, on Zulip):

like what kind of Try type would you use with a try level fn and where does it go

Yoshua Wuyts (May 04 2020 at 18:58, on Zulip):

I'm not sure what "level" refers to in this context

Jane Lusby (May 04 2020 at 18:58, on Zulip):

and i feel like if you're going to have a special syntax for type ascription on try blocks you'd want it to mirror the syntax on try functions

Jane Lusby (May 04 2020 at 18:58, on Zulip):

im not proposing that syntax

Jane Lusby (May 04 2020 at 18:58, on Zulip):

as in

Jane Lusby (May 04 2020 at 18:58, on Zulip):

specifying the Error type within the Try type

Jane Lusby (May 04 2020 at 18:58, on Zulip):

and specifying the try type itself

Jane Lusby (May 04 2020 at 18:59, on Zulip):

so the proposals you've mentioned in the past like fn foo() -> u32 throws Bar { presumably defaults to a Result

Jane Lusby (May 04 2020 at 18:59, on Zulip):

but how do you set it to something other than a Result?

Yoshua Wuyts (May 04 2020 at 18:59, on Zulip):

ah okay, think I'm following now (:

Jane Lusby (May 04 2020 at 19:00, on Zulip):

and if theres a clean solution there I feel like theres value in applying that same syntax to try blocks

Jane Lusby (May 04 2020 at 19:00, on Zulip):

in that you can only specify the Error type for From type inference

Jane Lusby (May 04 2020 at 19:00, on Zulip):

via throws or yeets or w/e

Josh Triplett (May 04 2020 at 19:01, on Zulip):

Yoshua Wuyts said:

(the rule being: if an error type is not specified we fall back to a generic "dyn Box Error type", whichever shape that might be)

That would be privileging a specific generic error type.

Yoshua Wuyts (May 04 2020 at 19:01, on Zulip):

@Josh Triplett yes it would, and I think there's a case to be made for that -- but that's a separate but related conversation

Yoshua Wuyts (May 04 2020 at 19:03, on Zulip):

I guess my overarching point is that a lot of error handling seems strongly connected, and I see value in approaching this from a place where we ask which end-user experience we want to provide -- and then working backward to how we can provide that

Josh Triplett (May 04 2020 at 19:04, on Zulip):

I definitely agree with that philosophy.

Josh Triplett (May 04 2020 at 19:05, on Zulip):

I have thoughts on what the end-user experience should look and feel like, but I absolutely agree that experience should come first.

Yoshua Wuyts (May 04 2020 at 19:05, on Zulip):

Might very well be that throws is not the best outcome for Rust, but I'd love that to be a conscious decision where we have decided it doesn't fit well in the larger picture for error handling rather than as an accident because we happened to go in a different direction.

Jane Lusby (May 04 2020 at 19:05, on Zulip):

I'm not convinced that defaulting to box<dyn error> achieves this objective

Josh Triplett (May 04 2020 at 19:07, on Zulip):

Yeah, to the extent throws seems plausible at all, "less magic" seems more likely to succeed. :)

Yoshua Wuyts (May 04 2020 at 19:08, on Zulip):

@Jane Lusby heh, yeah didn't necessarily want to advocate that it does here and now -- but wanted to bring it up as an example of something that's been brought up before, and at least seems worth talking about in earnest

Jane Lusby (May 04 2020 at 19:08, on Zulip):

I definitely think rust needs to improve its story around "open set errors"

Yoshua Wuyts (May 04 2020 at 19:08, on Zulip):

(it's past working hours for me here; going to log off again -- ttyl!)

Jane Lusby (May 04 2020 at 19:08, on Zulip):

more specifically handlable ones

Jane Lusby (May 04 2020 at 19:09, on Zulip):

o/

Lokathor (May 04 2020 at 19:51, on Zulip):

Yoshua Wuyts said:

Something that I haven't seen brought up in discussions much, but still think is worth discussing is the option of making fn foo() throws {} use Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> as its return type

This would be a sad outcome for core, though I'm not sure how sad.

nikomatsakis (May 04 2020 at 21:32, on Zulip):

I think, @Jane Lusby, you were saying the same thing I was trying to say. That I would want to consider any type annotation syntax that one would use at fn level and mirror at the block level.

nikomatsakis (May 04 2020 at 21:33, on Zulip):

I also think that a default that is 'the dyn Error type' feels very useful; tbh, I found working with Fehler quite nice in this way. Being able to just annotate functions with #[throws] felt good. I actually even prefer that syntax to -> u32 throws {, which.. reads kind of strangely to me, though I might get used to it.

nikomatsakis (May 04 2020 at 21:33, on Zulip):

I was initially concerned about the need to accommodate functions that return Option and the like, but I'm less concerned about that now, it seems like a less common case, and requiring a bit of extra annotation might be ok

nikomatsakis (May 04 2020 at 21:34, on Zulip):

In any case, I very much agree that it's a good idea to start from a place of sketching out the end-user experience we're looking for.

nikomatsakis (May 04 2020 at 21:35, on Zulip):

This btw is precisely the sort of case I was thinking about when suggesting that we can use procedural macros (and perhaps "core features" that we export in an intentionally odd-ball way) to help drive user-space experimentation and for all of us to gain a better feel of what it's like to use features in practice, versus arguing from theory. (In my ideal world, we'd even run some limited experiments of teaching folks to use different systems...)

nikomatsakis (May 04 2020 at 21:36, on Zulip):

In this case, we may not need much beyond what Fehler already provides, I suppose, though I think that plausibly a "core version" of try blocks might help -- maybe just the ability to break-with-value

rpjohnst (May 05 2020 at 23:32, on Zulip):

nikomatsakis said:

I think, Jane Lusby, you were saying the same thing I was trying to say. That I would want to consider any type annotation syntax that one would use at fn level and mirror at the block level.

This line of thinking suggests to me that there might be some useful parallels with closures- those also default to no annotation but allow you to specify a return type with ->, which is also the same as the one you use at fn level. Maybe there are some common patterns people have found for using ? in closures?

rpjohnst (May 05 2020 at 23:33, on Zulip):

(Closures would also presumably inherit any sort of fn decl syntax for throws/try/whatever else?)

simulacrum (May 06 2020 at 11:55, on Zulip):

I very rarely get to use ? in closures because the majority of closures I write don't get to return result - e.g. in iterator adapters. Most of the time that means rewriting as a for loop or so.

nikomatsakis (May 06 2020 at 14:13, on Zulip):

sigh, so true

Josh Triplett (May 06 2020 at 16:07, on Zulip):

Yeah, same problem here. I wanted to be able to use .unwrap_or_else on an Option, but the closure needed to use ?, so I had to write an explicit match.

nikomatsakis (May 07 2020 at 14:30, on Zulip):

So, I'd like to post the meeting video and some notes -- I'm wondering if folks agree with my takeaways -- I guess I'll reskim the comments here, but I don't feel like they had any missing notes.

scottmcm (May 09 2020 at 19:28, on Zulip):

Josh Triplett said:

Yeah, same problem here. I wanted to be able to use .unwrap_or_else on an Option, but the closure needed to use ?, so I had to write an explicit match.

I really wish we just had opt ☃ "hello".to_string() instead of opt.unwrap_or_else(|| "hello".to_string()). Then it wouldn't have all the closure barriers, so it could ?, return, yeet, ...

scottmcm (May 09 2020 at 19:31, on Zulip):

I was just writing a table that was similar to this:

|| { 4 }
async { 4 }
try { 4 }
const { 4 }

So the closure made me think about try -> TypeHere { 4 } as ascription syntax for try. Dunno if that's a good idea, or a terrible one because of the return-type-sugar conversations.

Taylor Cramer (May 11 2020 at 21:37, on Zulip):

I'm personally a fan (of the -> Ty syntax)

Taylor Cramer (May 11 2020 at 21:38, on Zulip):

but I also vaguely want it to match the type ascription syntax

Taylor Cramer (May 11 2020 at 21:38, on Zulip):

(which could also be ->, but I know there has been controversy over this)

nikomatsakis (May 11 2020 at 21:42, on Zulip):

I would say that -> is not a bad idea, but I would expect that if we permitted

try fn foo() -> T

and

try -> T {
}

that the meaning of those T types ought to match, right?

scottmcm (May 13 2020 at 18:39, on Zulip):

Agreed, niko. That's what worried me about it, because it implies solving try -> u64 throws io::Error or similar as part of the try block itself, which would be nice to avoid, since the ok type isn't the interesting part of the ascription for the block.

scottmcm (May 13 2020 at 18:41, on Zulip):

So (assuming for this post that we want that sugar) I'd probably end up writing something more like try -> _ throws anyhow::Error most often, which seems a bit odd to me for some reason.

scottmcm (May 13 2020 at 18:44, on Zulip):

Unbaked musing: maybe a syntax that doesn't require mentioning the ok type at all, since that's better specified in the body or via context anyway? Strawman try ☃ std::io::Result { ... }, where you pass a generic type with one parameter? ( could be in or something, but that's not important.)

Sebastian Malton (May 13 2020 at 19:00, on Zulip):

I think that it would also be nice if in the simple case, where all the Err types in a try { ... } are exactly the same, such a decl would not be needed

scottmcm (May 13 2020 at 22:24, on Zulip):

Agreed, @Sebastian Malton -- that was one of the things on the wishlist for discussion in the meeting.

It's challenging because the From::from is currently part of the ?. The simplest fix I could think of would be to have try { (a?, b?) } be different from try ☃ SomeType { (a?, b?) } (so that the former wouldn't do error- or carrier-conversion), but that implies that try ☃ _ { ... } and try { ... } would be different, which also seems suboptimal.

Sebastian Malton (May 13 2020 at 22:32, on Zulip):

Maybe, though I don't think that suboptimal. Especially since we are talking about type ascription in the first place, leaving it as _ in try ☃ _ seems like it would never work anyway.

scottmcm (May 13 2020 at 22:33, on Zulip):

Hmm, that's an interesting observation :thumbs_up:

nikomatsakis (May 15 2020 at 16:04, on Zulip):

scottmcm said:

So (assuming for this post that we want that sugar) I'd probably end up writing something more like try -> _ throws anyhow::Error most often, which seems a bit odd to me for some reason.

imo what this argues for is

  1. anyhow should move into libstd, let's say as std::error::Any
  2. throws std::error::Any (or whatever) would be the default
nikomatsakis (May 15 2020 at 16:05, on Zulip):

I would also say that even if we don't use -> notation, it would seem best for try fn (should it exist) and type ascription on try to line up

nikomatsakis (May 15 2020 at 16:05, on Zulip):

I feel like we need to go over this thread and do a write-up with key points etc

Lokathor (May 15 2020 at 16:15, on Zulip):

What does core do though?

nikomatsakis (May 15 2020 at 16:16, on Zulip):

idk we have to figure it out :)

nikomatsakis (May 15 2020 at 16:16, on Zulip):

maybe if you opt out from libstd you have to specify your error type yourself

Jane Lusby (May 15 2020 at 16:34, on Zulip):

(deleted)

Josh Triplett (May 15 2020 at 17:21, on Zulip):

Not to bikeshed, but we shouldn't call it Any, because we have something by that name already.

pnkfelix (May 15 2020 at 17:40, on Zulip):

(did that stop us with io::Result ... :wink: )

Jane Lusby (May 15 2020 at 17:49, on Zulip):

I am going to do the bit where I say I think we should call it Report

nikomatsakis (May 15 2020 at 21:28, on Zulip):

indeed we can't call it any, I know

Josh Triplett (May 15 2020 at 21:32, on Zulip):

@pnkfelix I've experienced a great deal of pain caused by std::fmt::Write and std::io::Write.

cuviper (May 15 2020 at 21:36, on Zulip):

gotta write the right Write, right?

Lokathor (May 15 2020 at 21:53, on Zulip):

I think that the best thing for the long term health of Rust is for code to be as no_std as possible as often as possible "by default".

So any solution which is, uh, "inclined" (to pick as neutral a term as possible) against giving a smooth no_std experience is a bad path for the language to take.

Last update: Jun 05 2020 at 22:50UTC