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

Overloadable Index #263

Open
lupan opened this issue May 17, 2021 · 7 comments
Open

Overloadable Index #263

lupan opened this issue May 17, 2021 · 7 comments
Labels
enhancement New feature or request

Comments

@lupan
Copy link

lupan commented May 17, 2021

This is 2 different things which I have used many times in lua for more powerful dynamic object handling, simply the act of overloading what happens when you use either object.whatever and object["whatever"], I have used this many times to write dynamic message systems via internal templates to create fully runtime handled objects, this is horrible to use in rust due to fact its a lot of function calls, but in scripting langs it is quite simple and beautiful, for example:

struct template { //for generating the msg at runtime
    name: String,
    fields: Vec<(String, TypeEnum)> //name and default value
}
struct dynamic_msg {
    template: Arc<template>,
    fields: HashMap<String, TypeEnum> //name of field and inner value (this is cloned from template)
}
impl dynamic_msg {
  fn set_dynamic_field(&mut self, name: &str, new_value: TypeEnum) -> Result<()> {
      self.fields[name] = new_value; //missed out the checks for simplicity sake
      Ok(())
  }
fn get_dynamic_field(&self, name: &str) -> Result<&TypeEnum> {
      let val = self.fields.get(name); //missed out the checks for simplicity sake
      Ok(val)
  }
fn get_dynamic_field_mut(&mut self, name: &str) -> Result<&mut TypeEnum> {
      let val = self.fields.get_mut(name); //missed out the checks for simplicity sake
      Ok(val)
  }
}

in lua I usually override the index function on the userdata and make it simply run the set and get dynamic field functions, allowing me in lua to write this:

msg = create_msg("name")
msg.field = "potato"
etc etc
return msg

I realize this is possible using Object but that comes with 2 issues for me, one it doesn't handle if I try to access or create a field which isn't part of the msg, and it has to be parsed from and into the Object type, as for the dynamic struct system which is great, it requires the scripter to write the structs themselves.

p.s. this example above is purposely simple and far from what the optimized and expanded version would look like.

@LoopyAshy
Copy link

I actually agree with this; but only for the fact that Objects can already access their fields both via [name] and .name, overall this being a option on the INDEX_GET/INDEX_SET protocols would be wonderful. Lua indeed allows this feature so I am quite used to it and overall it makes the code much nicer to read and write along with maintaining safety, which is what a scripting language should be.

@udoprog udoprog added the enhancement New feature or request label Jul 5, 2021
@udoprog
Copy link
Collaborator

udoprog commented Jul 5, 2021

I'm not entirely following how this is different from the INDEX_SET and SET protocols (e.g. the former is object[key], the latter object.key).

Is this proposing that you should be able to do it in Rune without having to bind the protocols in a Rust module? If so, I think it would be covered by #23 since both INDEX_SET and SET would be expected to be protocols.

@LoopyAshy
Copy link

LoopyAshy commented Jul 5, 2021

I think the issue is that this example below doesn't work like it does in Lua which is usually done in Lua for more complex runtime generated "static" type behaviour by basically faking fields or running data whenever the type is used to get a field:

rust

pub struct example {
    map: HashMap<String, String>
}

impl example {
    fn get(&mut self, key: String) -> String {
        self.map.get(&key).unwrap().clone()
    }
}

let mut module = Module::new();
module.ty::<example>().expect("failed to add example struct");
module.inst_fn(Protocol::INDEX_GET, example::get).expect("failed to add INDEX_GET to example struct");
 //or: module.inst_fn(Protocol::GET, example::get).expect("failed to add GET to example struct");

rune

fn main(value) {
    //return value.a; //doesn't work
     return value["a"]; //does work
}

I know I have also done this technique before in past, so I can see the desire.

@udoprog
Copy link
Collaborator

udoprog commented Jul 5, 2021

Ah, right. So GET only works for specific fields. It would be plausible to add support though so that it can work as a regular instance fn, like so:

module.inst_fn(Protocol::GET, example::get);
module.inst_fn(Protocol::INDEX_GET, example::get);

It currently only works as a field function, but either its functionality could be extended to work as an instance fn or add another protocol.

@LoopyAshy
Copy link

LoopyAshy commented Jul 5, 2021

Ah, right. So GET only works for specific fields. It would be plausible to add support though so that it can work as a regular instance fn, like so:

module.inst_fn(Protocol::GET, example::get);
module.inst_fn(Protocol::INDEX_GET, example::get);

It currently only works as a field function, but either its functionality could be extended to work as an instance fn or add another protocol.

That sounds perfect to me; I have had to implement systems with a lot of different scripting languages within several projects I have worked on in the past, and out of all of them: Rune does seem like a winner (I love Rust's syntax regardless so I am bias), however I am very used to the aforementioned functionality and admittedly it's hard to go without; it makes the scripts syntax much more digestible for none-programmers I have worked with.

@schungx
Copy link

schungx commented Jul 5, 2021

Can the GET protocol default to INDEX_GET if the property access is not found?

@LoopyAshy
Copy link

LoopyAshy commented Jul 15, 2021

Can the GET protocol default to INDEX_GET if the property access is not found?

That is easily the best solution in my honest opinion.
I'd attempt to contribute and add this feature myself but unfortunately I am very busy with work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants