From f43c78b733634dc2c21faef615be04193d68caaa Mon Sep 17 00:00:00 2001
From: Lixou <82600264+DasLixou@users.noreply.github.com>
Date: Sun, 20 Aug 2023 18:46:35 +0200
Subject: [PATCH 01/16] Add `impl-trait-for-fn`
---
text/0000-impl-trait-for-fn.md | 90 ++++++++++++++++++++++++++++++++++
1 file changed, 90 insertions(+)
create mode 100644 text/0000-impl-trait-for-fn.md
diff --git a/text/0000-impl-trait-for-fn.md b/text/0000-impl-trait-for-fn.md
new file mode 100644
index 00000000000..50d03ee0117
--- /dev/null
+++ b/text/0000-impl-trait-for-fn.md
@@ -0,0 +1,90 @@
+- Feature Name: `impl-trait-for-fn`
+- Start Date: 2023-08-20
+- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000)
+- Rust Issue: N/A
+
+# Summary
+[summary]: #summary
+
+Support for implementing traits on functions
+
+# Motivation
+[motivation]: #motivation
+
+I was trying to make something similar to bevy's system functions. And for safety reasons, they check for conflicts between SystemParams, so that a function requiring `Res` and `ResMut` [panic](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ecs/src/system/system_param.rs#L421).
+
+Then after I heard about axum's [`#[debug_handler]`](https://docs.rs/axum/latest/axum/attr.debug_handler.html) I wanted to do something similar to my copy of bevy systems, so that I get compile time errors when there is a conflict. I wanted even more, I wanted to force the user to mark the function with a specific proc attribute macro in order to make it possible to pass it into my code and call itself a system.
+
+# Guide-level explanation
+[guide-level-explanation]: #guide-level-explanation
+
+As we all know, you can implement a trait for a struct with the following syntax
+```rust
+struct Timmy;
+impl Person for Timmy {
+ fn greet() {
+ println!("Hey it's me, Timmy!");
+ }
+}
+```
+And we can also implement a trait for all functions with a specific signature like this
+```rust
+impl ValidSignature for F
+ where F: Fn(i32) -> bool
+{
+ /* ... */
+}
+```
+Now we can also implement traits for specific functions only
+```rust
+fn valid() {}
+impl ValidFunction for fn valid {
+ /* ... */
+}
+```
+
+# Reference-level explanation
+[reference-level-explanation]: #reference-level-explanation
+
+It gives the possibility to also implement a trait directly scoped to a function instead of generic implementation of multiple. Other than that, it basically behaves the same. It should also be possible to implement them via proc attribute macros:
+```rust
+#[impl_debug_name = "Greeting"]
+fn greet() {
+ /* ... */
+}
+// should expand to something like
+fn greet() {
+ /* ... */
+}
+impl FnDebugName for fn greet() {
+ fn debug_name() -> &'static str {
+ "Greeting"
+ }
+}
+```
+
+# Drawbacks
+[drawbacks]: #drawbacks
+
+i dont know any
+
+# Rationale and alternatives
+[rationale-and-alternatives]: #rationale-and-alternatives
+
+I think it's a easy task because we can already implement traits for a group of functions with the same signature, so why shouldn't we also implement single scoped impls?
+
+# Prior art
+[prior-art]: #prior-art
+
+i dont know any
+
+# Unresolved questions
+[unresolved-questions]: #unresolved-questions
+
+- Is the syntax good? I feel like we could drop the `fn` to from `impl Trait for fn function` to `impl Trait for function`.
+- What about closures? They don't even have names so targetting them would be quite difficult. I wouldn't want to use the compiler generated mess of a name like `[closure@src/main.rs:13:18: 13:20]`. It would also contain line numbers which would be changing quite often so thats not ideal.
+
+# Future possibilities
+[future-possibilities]: #future-possibilities
+
+- also make it possible to implement traits for closures directly.
\ No newline at end of file
From ae0d1373bffb6227ab02511b6a19cc26cf825910 Mon Sep 17 00:00:00 2001
From: Lixou <82600264+DasLixou@users.noreply.github.com>
Date: Sun, 20 Aug 2023 18:48:34 +0200
Subject: [PATCH 02/16] Add PR number
---
text/{0000-impl-trait-for-fn.md => 3476-impl-trait-for-fn.md} | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
rename text/{0000-impl-trait-for-fn.md => 3476-impl-trait-for-fn.md} (97%)
diff --git a/text/0000-impl-trait-for-fn.md b/text/3476-impl-trait-for-fn.md
similarity index 97%
rename from text/0000-impl-trait-for-fn.md
rename to text/3476-impl-trait-for-fn.md
index 50d03ee0117..f986045b9ab 100644
--- a/text/0000-impl-trait-for-fn.md
+++ b/text/3476-impl-trait-for-fn.md
@@ -1,6 +1,6 @@
- Feature Name: `impl-trait-for-fn`
- Start Date: 2023-08-20
-- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000)
+- RFC PR: [rust-lang/rfcs#3476](https://github.com/rust-lang/rfcs/pull/3476)
- Rust Issue: N/A
# Summary
From b2c592b1c05d7cb125a9a36c7472a87b2196e6c1 Mon Sep 17 00:00:00 2001
From: Lixou <82600264+DasLixou@users.noreply.github.com>
Date: Tue, 22 Aug 2023 08:50:15 +0200
Subject: [PATCH 03/16] Make impl for more described functions clearer
---
text/3476-impl-trait-for-fn.md | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/text/3476-impl-trait-for-fn.md b/text/3476-impl-trait-for-fn.md
index f986045b9ab..937700ef1b6 100644
--- a/text/3476-impl-trait-for-fn.md
+++ b/text/3476-impl-trait-for-fn.md
@@ -46,6 +46,14 @@ impl ValidFunction for fn valid {
# Reference-level explanation
[reference-level-explanation]: #reference-level-explanation
+When the function has parameters, modifiers or a return type, it should not be included in the impl block, because the path is already unique
+```rust
+async fn request_name(id: PersonID) -> String { .. }
+
+impl Requestable for fn request_name {
+ /* ... */
+}
+```
It gives the possibility to also implement a trait directly scoped to a function instead of generic implementation of multiple. Other than that, it basically behaves the same. It should also be possible to implement them via proc attribute macros:
```rust
#[impl_debug_name = "Greeting"]
From add0ca5dd303f6af217a43bd6c143e227bc7f918 Mon Sep 17 00:00:00 2001
From: Lixou <82600264+DasLixou@users.noreply.github.com>
Date: Tue, 22 Aug 2023 09:14:08 +0200
Subject: [PATCH 04/16] Fix mistakes
---
text/3476-impl-trait-for-fn.md | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/text/3476-impl-trait-for-fn.md b/text/3476-impl-trait-for-fn.md
index 937700ef1b6..769a23843b4 100644
--- a/text/3476-impl-trait-for-fn.md
+++ b/text/3476-impl-trait-for-fn.md
@@ -46,6 +46,9 @@ impl ValidFunction for fn valid {
# Reference-level explanation
[reference-level-explanation]: #reference-level-explanation
+It gives the possibility to also implement a trait directly scoped to a function instead of generic implementation of multiple. Other than that, it basically behaves the same.
+
+
When the function has parameters, modifiers or a return type, it should not be included in the impl block, because the path is already unique
```rust
async fn request_name(id: PersonID) -> String { .. }
@@ -54,7 +57,7 @@ impl Requestable for fn request_name {
/* ... */
}
```
-It gives the possibility to also implement a trait directly scoped to a function instead of generic implementation of multiple. Other than that, it basically behaves the same. It should also be possible to implement them via proc attribute macros:
+It should also be possible to implement them via proc attribute macros:
```rust
#[impl_debug_name = "Greeting"]
fn greet() {
@@ -64,7 +67,7 @@ fn greet() {
fn greet() {
/* ... */
}
-impl FnDebugName for fn greet() {
+impl FnDebugName for fn greet {
fn debug_name() -> &'static str {
"Greeting"
}
From 2f7c0bd4e8a03e9bf64198ccb01377fb2a891548 Mon Sep 17 00:00:00 2001
From: Lixou <82600264+DasLixou@users.noreply.github.com>
Date: Tue, 22 Aug 2023 09:21:45 +0200
Subject: [PATCH 05/16] Add more examples for more cases
---
text/3476-impl-trait-for-fn.md | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/text/3476-impl-trait-for-fn.md b/text/3476-impl-trait-for-fn.md
index 769a23843b4..f6e0270eca5 100644
--- a/text/3476-impl-trait-for-fn.md
+++ b/text/3476-impl-trait-for-fn.md
@@ -57,6 +57,25 @@ impl Requestable for fn request_name {
/* ... */
}
```
+When the function is for example in a different mod, it should be referenced by its path
+```rust
+mod sub {
+ fn sub_mod_fn() { .. }
+}
+impl OutOfNamesRunnable for fn sub::sub_mod_fn {
+ /* ... */
+}
+```
+Just like how a fn inside an impl block still implements the Fn trait, it should also be possible to implement traits for them
+```rust
+struct MyStruct;
+impl MyStruct {
+ fn new() -> Self { Self }
+}
+impl Creatable for fn MyStruct::new {
+ /* ... */
+}
+```
It should also be possible to implement them via proc attribute macros:
```rust
#[impl_debug_name = "Greeting"]
From f13f239cf042a16445df2aed8727ce22717986af Mon Sep 17 00:00:00 2001
From: Lixou <82600264+DasLixou@users.noreply.github.com>
Date: Tue, 22 Aug 2023 15:45:40 +0200
Subject: [PATCH 06/16] Elaborate where to bind the trait to
---
text/3476-impl-trait-for-fn.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/text/3476-impl-trait-for-fn.md b/text/3476-impl-trait-for-fn.md
index f6e0270eca5..bc7e090f8dd 100644
--- a/text/3476-impl-trait-for-fn.md
+++ b/text/3476-impl-trait-for-fn.md
@@ -46,8 +46,8 @@ impl ValidFunction for fn valid {
# Reference-level explanation
[reference-level-explanation]: #reference-level-explanation
-It gives the possibility to also implement a trait directly scoped to a function instead of generic implementation of multiple. Other than that, it basically behaves the same.
-
+It gives the possibility to also implement a trait directly scoped to a function instead of generic implementation of multiple.
+When writing `impl MyTrait for fn func`, the `MyTrait` trait will be implemented for the type behind the function `func`.
When the function has parameters, modifiers or a return type, it should not be included in the impl block, because the path is already unique
```rust
@@ -117,4 +117,4 @@ i dont know any
# Future possibilities
[future-possibilities]: #future-possibilities
-- also make it possible to implement traits for closures directly.
\ No newline at end of file
+- also make it possible to implement traits for closures directly.
From 7b7aebb6973c2104746208ca52794872071b673e Mon Sep 17 00:00:00 2001
From: Lixou <82600264+DasLixou@users.noreply.github.com>
Date: Tue, 22 Aug 2023 16:48:20 +0200
Subject: [PATCH 07/16] Elaborate the RFC to a larger topic
---
text/3476-expose-fn-type.md | 147 +++++++++++++++++++++++++++++++++
text/3476-impl-trait-for-fn.md | 120 ---------------------------
2 files changed, 147 insertions(+), 120 deletions(-)
create mode 100644 text/3476-expose-fn-type.md
delete mode 100644 text/3476-impl-trait-for-fn.md
diff --git a/text/3476-expose-fn-type.md b/text/3476-expose-fn-type.md
new file mode 100644
index 00000000000..dde650d2f2a
--- /dev/null
+++ b/text/3476-expose-fn-type.md
@@ -0,0 +1,147 @@
+- Feature Name: `expose-fn-type`
+- Start Date: 2023-08-20
+- RFC PR: [rust-lang/rfcs#3476](https://github.com/rust-lang/rfcs/pull/3476)
+- Rust Issue: N/A
+
+# Summary
+[summary]: #summary
+
+This exposes the ghost-/inner-/localtype of a function to the user.
+
+# Motivation
+[motivation]: #motivation
+
+I was trying to make something similar to bevy's system functions. And for safety reasons, they check for conflicts between SystemParams, so that a function requiring `Res` and `ResMut` [panic](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ecs/src/system/system_param.rs#L421).
+
+Then after I heard about axum's [`#[debug_handler]`](https://docs.rs/axum/latest/axum/attr.debug_handler.html) I wanted to do something similar to my copy of bevy systems, so that I get compile time errors when there is a conflict. I wanted even more, I wanted to force the user to mark the function with a specific proc attribute macro in order to make it possible to pass it into my code and call itself a system.
+
+For that, I would need to mark the type behind the function, for example, with a trait.
+
+# Guide-level explanation
+[guide-level-explanation]: #guide-level-explanation
+
+As we all know, you can refer to a struct by its name and for example implement a trait
+```rust
+struct Timmy;
+impl Person for Timmy {
+ fn greet() {
+ println!("Hey it's me, Timmy!");
+ }
+}
+```
+When we want to target a specific function for a trait implementation, we somehow need to get to the type behind it. That is being done with the `fn` keyword as follows
+```rust
+fn my_function() {}
+impl MyTrait for fn my_function {
+ /* ... */
+}
+```
+---
+For a better understanding, imagine you have a struct like this:
+```rust
+struct FnContainer {
+ inner: F,
+}
+fn goods() { }
+
+let contained_goods = FnContainer {
+ inner: goods
+};
+```
+Here, we make a `FnContainer` which can hold every function with the signature `() -> ()` via generics.
+But what about explicitly designing the `FnContainer` for a specific function, just like the compiler does when resolving the generics. This will work the same as with the trait impl from above:
+```rust
+struct GoodsContainer {
+ inner: fn goods,
+}
+fn goods() {}
+
+let contained_goods = GoodsContainer {
+ inner: goods,
+}
+```
+---
+A function with a more complex signature, like with parameters, modifiers or a return type, is still just referenced by its name, because it's already unique
+```rust
+async fn request_name(id: PersonID) -> String { .. }
+
+impl Requestable for fn request_name {
+ /* ... */
+}
+```
+
+# Reference-level explanation
+[reference-level-explanation]: #reference-level-explanation
+
+As described in the **Guide-level explanation**, with the syntax `fn `, we can reference the type behind the named function.
+
+When the function is for example in a different mod, it should be referenced by its path
+```rust
+mod sub {
+ fn sub_mod_fn() { .. }
+}
+impl fn sub::sub_mod_fn {
+ /* ... */
+}
+```
+
+It should be also possible to get the type of functions inside impl blocks:
+
+```rust
+struct MyStruct;
+impl MyStruct {
+ fn new() -> Self { Self }
+}
+impl fn MyStruct::new {
+ /* ... */
+}
+```
+
+Just as structs and enums have the possibility to derive traits to automatically generate code, function type do too
+
+```rust
+#[derive(DbgSignature)]
+fn signature_test(val: i32) -> bool {
+ /* ... */
+}
+
+// Expands to
+
+fn signature_test(val: i32) -> bool {
+ /* ... */
+}
+impl DbgSignature for fn signature_test {
+ fn dbg_signature() -> &'static str {
+ "fn signature_test(val: i32) -> bool"
+ }
+}
+```
+
+Other than that, it should behave like every other type does.
+
+# Drawbacks
+[drawbacks]: #drawbacks
+
+- When introducing the derive feature, it could lead to parsing problems with proc macros having an older `syn` crate version.
+
+# Rationale and alternatives
+[rationale-and-alternatives]: #rationale-and-alternatives
+
+The type behind functions already exists, we just need to expose it to the user.
+The hard part would be allowing derives, because that may break some things.
+
+# Prior art
+[prior-art]: #prior-art
+
+i dont know any
+
+# Unresolved questions
+[unresolved-questions]: #unresolved-questions
+
+- Is the syntax good? It could create confusion between a function pointer.
+- What about closures? They don't even have names so targetting them would be quite difficult. I wouldn't want to use the compiler generated mess of a name like `[closure@src/main.rs:13:18: 13:20]`. It would also contain line numbers which would be changing quite often so thats not ideal.
+
+# Future possibilities
+[future-possibilities]: #future-possibilities
+
+- Also expose the type of closures
diff --git a/text/3476-impl-trait-for-fn.md b/text/3476-impl-trait-for-fn.md
deleted file mode 100644
index bc7e090f8dd..00000000000
--- a/text/3476-impl-trait-for-fn.md
+++ /dev/null
@@ -1,120 +0,0 @@
-- Feature Name: `impl-trait-for-fn`
-- Start Date: 2023-08-20
-- RFC PR: [rust-lang/rfcs#3476](https://github.com/rust-lang/rfcs/pull/3476)
-- Rust Issue: N/A
-
-# Summary
-[summary]: #summary
-
-Support for implementing traits on functions
-
-# Motivation
-[motivation]: #motivation
-
-I was trying to make something similar to bevy's system functions. And for safety reasons, they check for conflicts between SystemParams, so that a function requiring `Res` and `ResMut` [panic](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ecs/src/system/system_param.rs#L421).
-
-Then after I heard about axum's [`#[debug_handler]`](https://docs.rs/axum/latest/axum/attr.debug_handler.html) I wanted to do something similar to my copy of bevy systems, so that I get compile time errors when there is a conflict. I wanted even more, I wanted to force the user to mark the function with a specific proc attribute macro in order to make it possible to pass it into my code and call itself a system.
-
-# Guide-level explanation
-[guide-level-explanation]: #guide-level-explanation
-
-As we all know, you can implement a trait for a struct with the following syntax
-```rust
-struct Timmy;
-impl Person for Timmy {
- fn greet() {
- println!("Hey it's me, Timmy!");
- }
-}
-```
-And we can also implement a trait for all functions with a specific signature like this
-```rust
-impl ValidSignature for F
- where F: Fn(i32) -> bool
-{
- /* ... */
-}
-```
-Now we can also implement traits for specific functions only
-```rust
-fn valid() {}
-impl ValidFunction for fn valid {
- /* ... */
-}
-```
-
-# Reference-level explanation
-[reference-level-explanation]: #reference-level-explanation
-
-It gives the possibility to also implement a trait directly scoped to a function instead of generic implementation of multiple.
-When writing `impl MyTrait for fn func`, the `MyTrait` trait will be implemented for the type behind the function `func`.
-
-When the function has parameters, modifiers or a return type, it should not be included in the impl block, because the path is already unique
-```rust
-async fn request_name(id: PersonID) -> String { .. }
-
-impl Requestable for fn request_name {
- /* ... */
-}
-```
-When the function is for example in a different mod, it should be referenced by its path
-```rust
-mod sub {
- fn sub_mod_fn() { .. }
-}
-impl OutOfNamesRunnable for fn sub::sub_mod_fn {
- /* ... */
-}
-```
-Just like how a fn inside an impl block still implements the Fn trait, it should also be possible to implement traits for them
-```rust
-struct MyStruct;
-impl MyStruct {
- fn new() -> Self { Self }
-}
-impl Creatable for fn MyStruct::new {
- /* ... */
-}
-```
-It should also be possible to implement them via proc attribute macros:
-```rust
-#[impl_debug_name = "Greeting"]
-fn greet() {
- /* ... */
-}
-// should expand to something like
-fn greet() {
- /* ... */
-}
-impl FnDebugName for fn greet {
- fn debug_name() -> &'static str {
- "Greeting"
- }
-}
-```
-
-# Drawbacks
-[drawbacks]: #drawbacks
-
-i dont know any
-
-# Rationale and alternatives
-[rationale-and-alternatives]: #rationale-and-alternatives
-
-I think it's a easy task because we can already implement traits for a group of functions with the same signature, so why shouldn't we also implement single scoped impls?
-
-# Prior art
-[prior-art]: #prior-art
-
-i dont know any
-
-# Unresolved questions
-[unresolved-questions]: #unresolved-questions
-
-- Is the syntax good? I feel like we could drop the `fn` to from `impl Trait for fn function` to `impl Trait for function`.
-- What about closures? They don't even have names so targetting them would be quite difficult. I wouldn't want to use the compiler generated mess of a name like `[closure@src/main.rs:13:18: 13:20]`. It would also contain line numbers which would be changing quite often so thats not ideal.
-
-# Future possibilities
-[future-possibilities]: #future-possibilities
-
-- also make it possible to implement traits for closures directly.
From 32dfb826801ae322ec238ab98ceda7b51929d1ed Mon Sep 17 00:00:00 2001
From: Lixou <82600264+DasLixou@users.noreply.github.com>
Date: Tue, 22 Aug 2023 19:43:11 +0200
Subject: [PATCH 08/16] Add examples for functions with generics
---
text/3476-expose-fn-type.md | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/text/3476-expose-fn-type.md b/text/3476-expose-fn-type.md
index dde650d2f2a..7d25d30e917 100644
--- a/text/3476-expose-fn-type.md
+++ b/text/3476-expose-fn-type.md
@@ -97,6 +97,22 @@ impl fn MyStruct::new {
}
```
+When a function has generics, they will be handled as follows, just like we know it from normal types
+```rust
+fn send(val: T) {}
+impl ParcelStation for fn send {
+ /* ... */
+}
+```
+
+When we have an implicit generic, they will be appended in order to the generic list:
+```rust
+fn implicit_generic(val: impl Clone) -> impl ToString {}
+impl for fn implicit_generic {
+ /* ... */
+}
+```
+
Just as structs and enums have the possibility to derive traits to automatically generate code, function type do too
```rust
@@ -140,6 +156,7 @@ i dont know any
- Is the syntax good? It could create confusion between a function pointer.
- What about closures? They don't even have names so targetting them would be quite difficult. I wouldn't want to use the compiler generated mess of a name like `[closure@src/main.rs:13:18: 13:20]`. It would also contain line numbers which would be changing quite often so thats not ideal.
+- I provided a possible solution for a `fn implicit_generic(val: impl Clone) -> impl ToString` function, but because we currently don't have a defined syntax for those generics in types, thus we can't use `impl Trait` as types for fields in structs, we should think about this more, maybe don't implement exposed types of function for such `fn`s and wait for another RFC?
# Future possibilities
[future-possibilities]: #future-possibilities
From adb2c957ea2321ccbddebed7c5fff08ec09212ae Mon Sep 17 00:00:00 2001
From: Lixou <82600264+DasLixou@users.noreply.github.com>
Date: Fri, 25 Aug 2023 12:47:38 +0200
Subject: [PATCH 09/16] Update text/3476-expose-fn-type.md
Co-authored-by: Jonathan Chan Kwan Yin
---
text/3476-expose-fn-type.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/text/3476-expose-fn-type.md b/text/3476-expose-fn-type.md
index 7d25d30e917..5d05672d95d 100644
--- a/text/3476-expose-fn-type.md
+++ b/text/3476-expose-fn-type.md
@@ -45,7 +45,7 @@ struct FnContainer {
fn goods() { }
let contained_goods = FnContainer {
- inner: goods
+ inner: goods,
};
```
Here, we make a `FnContainer` which can hold every function with the signature `() -> ()` via generics.
From 19dba3644f2e9c556eb116f3499261a0fc85b69e Mon Sep 17 00:00:00 2001
From: Lixou <82600264+DasLixou@users.noreply.github.com>
Date: Fri, 25 Aug 2023 12:53:45 +0200
Subject: [PATCH 10/16] Update text/3476-expose-fn-type.md
Co-authored-by: Jonathan Chan Kwan Yin
---
text/3476-expose-fn-type.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/text/3476-expose-fn-type.md b/text/3476-expose-fn-type.md
index 5d05672d95d..183719c0980 100644
--- a/text/3476-expose-fn-type.md
+++ b/text/3476-expose-fn-type.md
@@ -85,7 +85,7 @@ impl fn sub::sub_mod_fn {
}
```
-It should be also possible to get the type of functions inside impl blocks:
+It should be also possible to get the type of associated functions:
```rust
struct MyStruct;
From fc69e90f9c34471b32982234f073df1069fa5ac6 Mon Sep 17 00:00:00 2001
From: Lixou <82600264+DasLixou@users.noreply.github.com>
Date: Fri, 25 Aug 2023 13:49:26 +0200
Subject: [PATCH 11/16] Apply suggestions
---
text/3476-expose-fn-type.md | 109 ++++++++++++++++++++++++------------
1 file changed, 72 insertions(+), 37 deletions(-)
diff --git a/text/3476-expose-fn-type.md b/text/3476-expose-fn-type.md
index 183719c0980..aa37003caed 100644
--- a/text/3476-expose-fn-type.md
+++ b/text/3476-expose-fn-type.md
@@ -6,7 +6,7 @@
# Summary
[summary]: #summary
-This exposes the ghost-/inner-/localtype of a function to the user.
+This exposes the function type of a function item to the user.
# Motivation
[motivation]: #motivation
@@ -15,7 +15,19 @@ I was trying to make something similar to bevy's system functions. And for safet
Then after I heard about axum's [`#[debug_handler]`](https://docs.rs/axum/latest/axum/attr.debug_handler.html) I wanted to do something similar to my copy of bevy systems, so that I get compile time errors when there is a conflict. I wanted even more, I wanted to force the user to mark the function with a specific proc attribute macro in order to make it possible to pass it into my code and call itself a system.
-For that, I would need to mark the type behind the function, for example, with a trait.
+For that, I would need to mark the type behind the function item, for example, with a trait.
+
+# Terminology
+
+I'll may shorten `function` to `fn` sometimes.
+
+- **function pointer**: pointer type with the type syntax `fn(?) -> ?` directly pointing at a function, not the type implementing the `Fn[Once/Mut](?) -> ?` traits.
+- **function item** (or just function): a declared function in code. free-standing or associated to a type.
+- **function group**: many non-specific functions with the same signature (params, return type, etc.)
+- **function trait(s)**: the `Fn[Once/Mut](?) -> ?` traits
+- **function type**: the type behind a function, which also implements the function traits.
+- **fixed type**: directly named type, no generic / `impl Trait`.
+- **describe the function type**: write `fn(..) -> ? name` instead of just `fn name`.
# Guide-level explanation
[guide-level-explanation]: #guide-level-explanation
@@ -29,43 +41,46 @@ impl Person for Timmy {
}
}
```
-When we want to target a specific function for a trait implementation, we somehow need to get to the type behind it. That is being done with the `fn` keyword as follows
+When we want to target a specific function for a trait implementation, we somehow need to get to the type behind it.
+Refering to the hidden type is achieved via the following syntax
```rust
-fn my_function() {}
-impl MyTrait for fn my_function {
+fn is_positive(a: i32) -> bool { /* ... */ }
+impl MyTrait for fn(i32) -> bool is_positive {
/* ... */
}
```
----
-For a better understanding, imagine you have a struct like this:
+For function signatures, where every parameter/return-type is a fixed type and can be known just by refering to the function (so no generics or `impl Trait` parameters/return type), we can drop the redundant information:
```rust
-struct FnContainer {
- inner: F,
+fn is_positive(a: i32) -> bool { /* ... */ }
+impl MyTrait for fn is_positive {
+ /* ... */
}
-fn goods() { }
+```
-let contained_goods = FnContainer {
- inner: goods,
-};
+> 💡 NOTE: Even when we need to describe the function type but the return type is `()`, we can (just as for function pointers and function traits) drop the `-> ()` from the type. (This should also be added as a lint).
+
+---
+A function with a more complex signature, like a const function, we just ignore that when naming the type:
+```rust
+const fn my_fn(a: i32) -> (i16, i16) { .. }
+impl MyTrait for fn my_fn {}
+// or with explicit declaration
+impl MyTrait for fn(i32) -> (i16, i16) my_fn { .. }
```
-Here, we make a `FnContainer` which can hold every function with the signature `() -> ()` via generics.
-But what about explicitly designing the `FnContainer` for a specific function, just like the compiler does when resolving the generics. This will work the same as with the trait impl from above:
+
+When having an async function, we in theory have a `impl Future