cda-group / arc

Programming Language for Continuous Deep Analytics
https://cda-group.github.io/arc/
44 stars 6 forks source link

RFC: Additional code generation macros #300

Closed segeljakt closed 1 year ago

segeljakt commented 3 years ago

In arcorn we have the following macros:

I think we could consider additionally to add macros for generating other kinds of boilerplate:

@frej Is there anything which is tedious in MLIR to generate?

frej commented 3 years ago

@frej Is there anything which is tedious in MLIR to generate?

The less details of the Rust implementation the MLIR-level needs to know the better it is.

If we have macros for sharing values, shouldn't we also have macros for accessing the boxed/rc:d value too? Or is that handled by some Rust magic?

segeljakt commented 3 years ago

Rust has automatic dereferencing for types which implement Deref and/or DerefMut.

Because

impl<T: ?Sized> Deref for Rc<T> {
    type Target = T;

    #[inline(always)]
    fn deref(&self) -> &T {
        &self.inner().value
    }
}

we can do

use std::rc::Rc;
use std::cell::RefCell;

struct Foo {
    x: i32,
    y: Rc<String>
}

fn main() {
    let a = Rc::new(Foo { x: 0, y: Rc::new("".to_owned())});
    let b = a.clone().x.clone();
    let c = a.clone().y.clone();
}
segeljakt commented 3 years ago

I suggest we skip RefCell mutability for the moment. It makes it slightly more annoying to generate, we would have to insert .borrow() and .borrow_mut() in places. I am not sure completely about how we should handle mutability yet. There are two cases to consider for structs:

var x = { a: 0, b: 5 };
x = { a: 5, b: 9 }; // OK
x.a = 9; // OK

In Rust both are allowed as long as x is mut. However if we wrap x inside an Rc then we cannot mutate its fields:

let mut x = Rc::new(Foo { a: 0, b: 5 });
x = Rc::new(Foo { a: 0, b: 5 }); // OK
x.a = 9; // not OK

Either we need to just wrap all fields in RefCell or UnsafeCell and enforce in the arc-script type system that this is not possible:

val x = { a: 0, b: 5 };
x.a = 9; // not OK

In Rust, it would look something like:

let mut x = Rc::new(Foo { a: RefCell::new(0), b: RefCell::new(5) });
x.a.borrow_mut() = RefCell::new(9);

Alternatively we could try using functional struct syntax but I am not sure about the performance.

let mut x = Rc::new(Foo { a: 0, b: 5 });
x = Rc::new(Foo { a: 9, ..x.as_ref().clone() }); // OK