Jules Bertholet
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # const traits model ## NB: syntax in this document This document defines a large amount of new syntax. This is for the sake of fully defining the underlying model. Only a small portion of the syntax should be stabilized in the near future. ## const vs runtime bounds ### Introduction Every function item in Rust has two sets of trait bounds: set $R$ determines the requirements for calling the function in a runtime context, and set $C$ for calling it in a const context. Wherever $C$ is satisfied, so is $R$; henceforth we will denote this $C ≥ R$. In today’s Rust, one of the following is always true: either $C = R$ (`const fn`s), or $C$ is impossible to satisfy (non-`const` `fn`s). Our aim is to change that: to introduce functions where $C > R$, but $C$ is still possible to satisfy. ### Syntax To indicate this, we attach `where` clauses to the `const` keyword specifically: ```rust (const where T: Bar) fn do_thing<T: Foo>() {} ``` The function above can be called with any `T: Foo` in a runtime context, but requires `T: Foo + Bar` in a const context. ```rust // The following are effectively equivalent (const where String: Copy) fn nonconst() {} fn nonconst() {} ``` ## `const fn` in traits A trait definition can contain both `const` and non-`const` `fn` items; the `const` keyword on the `const fn`s may or may not carry extra bounds. ```rust trait Trait { fn nonconst(); const fn fullyconst(); (const where T: Foo) fn sometimesconst<T>(); } ``` The bounds on the functions in the `impl` cannot be more restrictive than those in the trait definition: ```rust impl Trait for () { fn nonconst() {} fn fullyconst() {} // Error (const where T: Foo + Bar) fn sometimesconst<T>() {} // Error } ``` However, they can be *less* restrictive: ```rust impl Trait for () { const fn nonconst() {} // OK const fn fullyconst() {} const fn sometimesconst<T>() {} // OK } ``` ## `: const` bounds Consider the (simplifed) `Add` trait: ```rust pub trait Add { fn add(self, rhs: Self) -> Self; } ``` Some types can implement this with a `const fn`: ```rust impl Add for i32 { const fn add(self, rhs: Self) -> Self { // compiler intrinsic } } ``` But others cannot: ```rust impl Add for BigInt { fn add(self, rhs: Self) -> Self { // Implementation omitted } } ``` Consider the following function that uses `Add`: ```rust fn add_twice<T: Add>(a: T, b: T, c: T) -> T { a + b + c } ``` Let’s say we want to make this function usable in const contexts. To do this, we need some way to write a bound asserting that the `fn add` in `T`’s `add` impl is `const`. We write this `T::add: const`: ```rust (const where T::add: const) fn add_twice<T: Add>(a: T, b: T, c: T) -> T { a + b + c } ``` The function above requires `T: Add` in order to be called in a runtime context, and additionally needs the `Add` impl to have `const fn add()` in order to be called in a const context. ### What if the function has early-bound generic parameters? Consider the following trait: ```rust trait Trait { fn foo<T>(); } ``` The following is not legal: ```rust (const where T::foo: const) fn foo<T: Trait, U>() { // ^^^ERROR: Missing generics T::foo::<U>(); } ``` This reflects the fact that constness is a boolean property of fully-instantiated functions, but is not boolean with respect to generic `fn` items. Instead, you should write: ```rust (const where T::foo<U>: const) fn foo<T: Trait, U>() { // OK T::foo::<U>(); } ``` This also works: ```rust (const where for<U> T::foo<U>: const) fn foo<T: Trait>() { // OK T::foo::<u32>(); T::foo::<String>(); } ``` You can even do this: ```rust (const where for<U: Copy> T::foo<U>: const) fn foo<T: Trait>() { // OK T::foo::<u32>(); T::foo::<char>(); //T::foo::<String>(); // this call would not be legal } ``` ## Basic `const Trait` Returning to our `add` example, `T::add: const` is a little verbose. And if the trait had several methods we wanted to mention, it would get even worse. To alleviate this, we can define a trait alias: ```rust pub trait ConstAdd = Add where Self::add: const; (const where T: ConstAdd) fn add_twice<T: Add>(a: T, b: T, c: T) -> T { a + b + c } ``` For convenience, we introduce built-in syntax sugar for this pattern: `const trait`. ```rust pub const trait Add { ~const fn add(self, rhs: Self) -> Self; } ``` This desugars to an `Add` trait with the same semantics as our original trait, plus a `const Add` alias with the same semantics as `ConstAdd`. The `~const` in `~const fn add` indicates that the `add` function is required to be `const` for the `const Add` alias to be satisfied, but base `Add` does not require it. (You can think of the `~` in `~const` as being a “string” that “ties” the constness of the function to that of the outer trait.) Now, we can rewrite our `add_twice` like so: ```rust (const where T: const Add) fn add_twice<T: Add>(a: T, b: T, c: T) -> T { a + b + c } ``` This is still more verbose than we’d like; we will address that in the next section. ### More complicated `const trait` example This: ```rust const trait Trait { fn nonconst(); // Neither `Trait` nor `const Trait` require this to be `const` ~const fn maybeconst(); // Only `const Trait` requires this to be `const` const fn alwaysconst(); // `Trait` and `const Trait` require this to be `const` } ``` Desugars to approximately this: ```rust trait Trait { fn nonconst(); fn maybeconst(); const fn alwaysconst(); } // Actually called `const Trait` trait ConstTrait = Trait where Self::maybeconst: const; ``` ## `~const` bounds on `fn`s We want to make this less verbose: ```rust (const where T: const Add) fn add_twice<T: Add>(a: T, b: T, c: T) -> T { a + b + c } ``` To do so, we rewrite it as: ```rust const fn add_twice<T: ~const Add>(a: T, b: T, c: T) -> T { a + b + c } ``` `~const` inside an `fn`’s bounds means “the non-`const` form of the bound is required to call the function at runtime, but the `const` form is required at compile-time”. Again, the `~` serves to “tie” the two `const` keywords together. Just as the constness of a `const Trait` is dependent on the constness of its `~const fn`s, the constness of a `const fn` is dependent on its `~const` bounds. `~const` also works with method `const` bounds: ```rust // These two `fn`s are exactly equivalent const fn add_twice<T: Add>(a: T, b: T, c: T) -> T where T::add: ~const, { a + b + c } (const where T::add: const) fn add_twice<T: Add>(a: T, b: T, c: T) -> T { a + b + c } ``` ## Advanced `const Trait` ### `~const` method defaults Consider the (simplified) `PartialEq` trait: ```rust pub trait PartialEq { fn eq(&self, other: &Self) -> bool; fn ne(&self, other: &Self) -> bool { !(self.eq(other)) } } ``` We can `const`ify it like so: ```rust pub const trait PartialEq { ~const fn eq(&self, other: &Self) -> bool; ~const fn ne(&self, other: &Self) -> bool { !(self.eq(other)) } } ``` According to the rules we have established so far, this would desugar to approximately: ```rust pub trait PartialEq { fn eq(&self, other: &Self) -> bool; fn ne(&self, other: &Self) -> bool { !(self.eq(other)) } } // Actually called `const PartialEq` pub trait ConstPartialEq = PartialEq where Self::eq: const, Self::ne: const; ``` But there’s an issue. Let’s try implementing it: ```rust struct Foo(u32); impl PartialEq for Foo { const fn eq(&self, other: &Self) -> bool { self.0 == other.0 } } ``` With the default `ne` impl, this desugars to: ```rust struct Foo(u32); impl PartialEq for Foo { const fn eq(&self, other: &Self) -> bool { self.0 == other.0 } fn ne(&self, other: &Self) -> bool { !(self.eq(other)) } } ``` `ne` is not `const fn`, so this `PartialEq` impl is not `const`. To fix this problem, we make a small change to the rules. We say that, when a `~const fn` inside a trait has a default body, that default is implicitly `const fn` `where Self: ~const Trait` (where `Trait` is the trait containing the `fn` item). So our new `impl` desugaring would be: ```rust struct Foo(u32); impl PartialEq for Foo { const fn eq(&self, other: &Self) -> bool { self.0 == other.0 } const fn ne(&self, other: &Self) -> bool where Self: ~const PartialEq, { !(self.eq(other)) } } ``` Which in turn desugars to: ```rust struct Foo(u32); impl PartialEq for Foo { const fn eq(&self, other: &Self) -> bool { self.0 == other.0 } (const where Self: const PartialEq) fn ne(&self, other: &Self) -> bool { !(self.eq(other)) } } ``` Thanks to coinduction, the `Self: const PartialEq` bound is satisfied, so `ne` is `const fn` and the impl is `const PartialEq`. However, if we were to remove the `const` from `const fn eq()` in the impl, then `Self: const PartialEq` would become unsatisfiable, so `Foo::ne()` would effectively become fully non-`const`. ### `~const` supertraits Now let’s consider the `Eq` trait. It has no methods: ```rust trait Eq: PartialEq {} ``` Also consider this `Eq`-using function: ```rust fn is_equal<T: Eq>(a: T, b: T) -> bool { a == b } ``` To make this function work in `const`, we would write: ```rust const fn is_equal<T: Eq + ~const PartialEq>(a: T, b: T) -> bool { a == b } ``` This is verbose. We can shorten it by making `Eq` into a `const trait`: ```rust const trait Eq: ~const PartialEq {} ``` This desugars to approximately: ```rust pub trait Eq: PartialEq {} // Actually called `const Eq` pub trait ConstEq = Eq where Self: const PartialEq; ``` Now, we can write: ```rust const fn is_equal<T: ~const Eq>(a: T, b: T) -> bool { a == b } ``` ### `~const` bounds on `~const fn`s `~const fn`s can have `~const` bounds. ```rust const trait Trait { ~const fn foo<T: ~const Debug>(); } ``` This desugars to approximately: ```rust trait Trait { fn foo<T: Debug>(); } // Actually called `const Trait` trait ConstTrait = Trait where for<T: const Debug> Self::foo<T>: const; ``` ### Fully custom `const` bounds Just like `const fn`s, `const` traits can specify fully custom `where` clauses for their `const`ness. ```rust (const where Self: Foo) trait Bar { // ... } ``` This desugars to approximately: ```rust trait Bar { // ... } // Actually called `const Bar` trait ConstBar = Bar where Self: Foo; ``` ## Asserting `const`ness of an `impl` To assert that a trait `impl` is `const`, one can write `impl const Trait` instead of `impl Trait`. This asserts that `const Trait` is implemented whenever the `const` versions of all `~const` bounds on the `impl` block are satisfied. Such `impl` blocks can also contain `~const fn`s; functions denoted in this way inherit the `~const` bounds of the impl block. For example: ```rust struct Wrapper<T>(T); const trait Trait { ~const fn foo(self) -> Self; } impl<T: ~const Trait> const Trait for Wrapper<T> { ~const fn foo(self) -> Self { Self(self.0.foo()) } } ```

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully