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

Possibility of inferring all functions as maybe keyword #60

Open
0xForerunner opened this issue Aug 7, 2024 · 3 comments
Open

Possibility of inferring all functions as maybe keyword #60

0xForerunner opened this issue Aug 7, 2024 · 3 comments
Labels
question Further information is requested

Comments

@0xForerunner
Copy link

0xForerunner commented Aug 7, 2024

One common complaint I see about the keyword-generics-innitiative is that the syntax can be quite verbose. The core idea I have is to essentially treat all unmarked keyword functions as maybe keyword. A solution I've been exploring in my head looks something like this:

/// Not awaiting or otherwise using the future for this function
/// would result in a warning
async fn foo_async() {}

/// Can optionally be called in any context and can optionally be awaited
/// Notice that all regular functions would fall into this category
/// Hopefully no need for additional syntax here?
fn foo_maybe_async() {
   // Perhaps #[cfg(async)] makes more sense than `if ?async`
   if ?async {
       // Do some async stuff
   } else {
       // Do some sync stuff
   }
}

Awaiting a function which doesn't contain an `?async' block/section would result in a warning. Conversely, not awaiting a function which does contain an async block/section while inside an async context would also emit a warning. I imagine this style of implementation should be fully backwards compatible.

Perhaps there's something I'm missing here, but declaring a function signature like

?async fn maybe_async_foo(){}

or

#[maybe(async)]
fn maybe_async_bar(){}

seems superfluous.

Currently, the compiler can tell if a const fn is valid. So it would seem to me that it should also be able to validate if calling unmarked (maybe const) functions from within a const function is valid. I'll give an example:

This example would compile because the compiler could check that bar_maybe_const has a valid const implementation

/// Notice we are marking explicitly as const
const fn foo_const() -> usize {
    bar_maybe_const()
}

/// Notice we are leaving unmarked (maybe const)
fn bar_maybe_const() -> usize {
    if ?const {
        return 1
    } else {
        do_something_at_runtime()
    }
}

This example would error because the compiler could check that bar_maybe_const has no valid const implementation

/// Notice we are marking explicitly as const
const fn foo_const() -> usize {
    bar_maybe_const()
}

/// Notice we are leaving unmarked (maybe const)
fn bar_maybe_const() -> usize {
    // we don't provide a valid const implementation
    do_something_at_runtime() <-- Error: fn do_something_at_runtime is not const
}

This is just something that's been spinning in my head for a while and there's a good chance I'm not seeing the whole picture here. But I'd love to get your thoughts/opinions on this.

@0xForerunner 0xForerunner added the question Further information is requested label Aug 7, 2024
@clarfonthey
Copy link

My first impression is that this is an API nightmare, since defaulting to maybe means now everything that doesn't want to be maybe has to be explicitly marked.

Like, you've just moved the verbosity somewhere else, and effectively required it to be used more often.

@0xForerunner
Copy link
Author

0xForerunner commented Aug 7, 2024

now everything that doesn't want to be maybe has to be explicitly marked.

This isn't how I was envisioning it. You wouldn't have to declare non-async functions as the compiler would just infer them.
For example:

fn foo(){}

would be automatically inferred to be !async fn foo() -> ()

async fn foo(){
    bar().await
}

would be automatically inferred to be async fn foo() -> ()

fn foo(){
    if ?async {
        bar().await
    }
}

would be automatically inferred to be ?async fn foo() -> ()

@clarfonthey The point of my proposal here is to virtually eliminate adding extra syntax to function signatures and let the compiler figure it out.

@clarfonthey
Copy link

Oh, that makes more sense, although this would be unprecedented in the language, at least for regular functions, since the reason why they require annotations is purely for API documentation purposes and not because they can't infer them.

I can definitely see the argument of doing this for closures, though. Although I'm not exactly sure how useful maybe-async closures are in general.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants