Open tema3210 opened 4 years ago
How different would your proposed syntax and features be from https://github.com/dtolnay/reflect?
How different would your proposed syntax and features be from https://github.com/dtolnay/reflect?
Well, issue should be named "Compile-time introspection". My mistake.
Consider an example: `
struct MyStruct {
a: u64,
b: i32,
//etc
}
`
This should generate a static hashmap with string key naming the field and value storing the offset, (optional) metadata, attach this static data to struct via fn
returning refence to hashmap.
Value in hashmap should store offset: u64
and (optional) metadata String
(or parsed one, HashMap<String,String>
). Consider a trait ReflectField
with asociated types and methods returning offset, metadata.
So acessor function should look like:
unsafe fn GetField<S,F>(trg: &mut S,desc: ReflectField<F>)->(&mut F,HashMap<String,String>) {//impl}
Benefit from adding it in Std is that required reflection package which is present in most crates connected with SERialization (and DEserialization) will gone, instead of them all there will be one standart reflection package.
Why should field accessors be unsafe? It is not apparent to me that accessing fields directly would lead to undefined behavior.
@SOF3 because the struct whose field we want to change is taken by mut ref, it means that all introspection related things must be done in the same context, to avoid thing like changing field of unexisting struct. Internally this should work like "we take mut ref to struct we are changing, then simply adding offset and returning mut ref to field inside of struct", so gotten ref must not outlive mut ref to struct nor struct itself. Alternatively, we can use getter and setter patterns
Alternatively, we can use getter\setter pattern to create interface like
pub fn get<'a,T: Reflectable ,D>(trg: &'a mut T,name: String, data &'a mut D)->bool
.
(set has exactly the same signature)
No unsafe in case of getter\setter pattern(lifetimes is gurantee of safety).
Internally we would need to check type match as well as existance of field. We return bool to say whether data been transferred.
UPD:
Reflectable trait:
pub trait Reflectable{ fn getFieldsVault()->&'static HashMap<String,Descriptor>; }
Descriptor struct:
pub struct Descriptor{ offset: isize, type_id: TypeId, }
Sorry I didn't reply to your initial reply!
I think this proposal has promise, but I'm unsure whether it should be implemented as an RFC first and foremost.
Something like #[derive(Reflection)] struct MyStruct { a: u64, b: i32, //etc }
like you describe, could definitely be implemented in an external crate. Derives are stable, and using something like https://docs.rs/field-offset/0.1.1/field_offset/macro.offset_of.html or the proposed std offset_of! macro I think the metadata could definitely be provided.
If this was implemented as a separate crate, then it could be tested and refined - and then potentially added to std if that seemed useful. Or it could just live as an external crate, and be used as one?
The other thing you mention, replacing other kinds of reflection (like that in serde
), sounds nice but also not necessarily like a positive? Serde-style reflection based on derive macros makes code which can be optimized per-struct. It's super fast, and I don't see how we could achieve that same speed if figuring out the fields of a struct required a method call.
This proposal could be added in addition to other methods of compile-time reflection, but would it really be a good replacement for most others? If it requires calling a method and traversing a data structure, I can't see that being as fast as code which already knows all the fields.
Sorry I didn't reply to your initial reply!
I think this proposal has promise, but I'm unsure whether it should be implemented as an RFC first and foremost.
Something like
#[derive(Reflection)] struct MyStruct { a: u64, b: i32, //etc }
like you describe, could definitely be implemented in an external crate. Derives are stable, and using something like https://docs.rs/field-offset/0.1.1/field_offset/macro.offset_of.html or the proposed std offset_of! macro I think the metadata could definitely be provided.If this was implemented as a separate crate, then it could be tested and refined - and then potentially added to std if that seemed useful. Or it could just live as an external crate, and be used as one?
The other thing you mention, replacing other kinds of reflection (like that in
serde
), sounds nice but also not necessarily like a positive? Serde-style reflection based on derive macros makes code which can be optimized per-struct. It's super fast, and I don't see how we could achieve that same speed if figuring out the fields of a struct required a method call.This proposal could be added in addition to other methods of compile-time reflection, but would it really be a good replacement for most others? If it requires calling a method and traversing a data structure, I can't see that being as fast as code which already knows all the fields.
I have implementation which still need to have a macro to create Descriptor
struct, requires the RFC 1849 to be implemented(type checking is done with TypeId::of<>()
), addtitionally inside there a static HashMap
which must be createn in compile time, i.e it's const item. I think, one day this interface will be able to work with static strings just like they were const generic items.
I have interface + realization(not tested): lib.rs.zip Also i haven't implemented macros yet.
This proposal could be added in addition to other methods of compile-time reflection, but would it really be a good replacement for most others? If it requires calling a method and traversing a data structure, I can't see that being as fast as code which already knows all the fields.
We can implement it in a way suitable for const evaluating. Actually, some macro assembled const functions to check whether field is present, if yes, which offset it has, which TypeId
?, etc. Many things can be done at compile time, we should use this. However, my approach is heavily based on const-fn s, which are not stable at the moment of writing.
For anyone who comes across this, it's worth noting that a lot of discussion of a similar feature happened in https://internals.rust-lang.org/t/pre-rfc-runtime-reflection/11039. I'm not 100% sure whether that's a direct continuation of this issue or not.
I don't have anything to add beyond linking that thread, but I think the issues raised in the last few posts there, especially the ones by haohou and idubrov, should definitely be resolved before we can move forward on this (or not).
Go uses reflections for creating a JSON string from any defined struct. Solely of attributes that are publicly accessible. I like that. Opt-in reflections would be nice.
Go uses reflections for creating a JSON string from any defined struct. Solely of attributes that are publicly accessible. I like that. Opt-in reflections would be nice.
It will be waste of resources, since go's reflection is used to do ADT, introspection for SerDe analogs, etc. The primary use case in rust is to simplify and unify introspection. Also, due to generics introspection of everything will bloat binaries with metadata; And it is unclear how to handle generic structs (sadly, my signatures don't handle it at all).
Goal is to have ability to generate descriptive struct by macro(from std).
Reason is that in lot of crates there are impementations of compile time reflection not compatible with each other, so many developers just reinventing wheel.
Proposed features:
Reflector
trait instd
.fn
's to acess fields by name.P.S I won't propose implementation, because i can't imagine brige between compile time generics and runtime logic.