vmware / differential-datalog

DDlog is a programming language for incremental computation. It is well suited for writing programs that continuously update their output in response to input changes. A DDlog programmer does not write incremental algorithms; instead they specify the desired input-output mapping in a declarative manner.
MIT License
1.37k stars 117 forks source link

Allow user context in relation transformers #915

Open Kixiron opened 3 years ago

Kixiron commented 3 years ago

I've got a situation where I'd like to construct one of two different dataflows within a transformer based on the external context of the program. When in the program using ddlog is in CLI mode I want to construct one dataflow optimized for that and when it's in LSP mode I'd like to use another optimized implementation. Being able to pass context to application nodes would allow this, maybe something along these lines:

use type_map::concurrent::TypeMap;
use std::any::Any;

// DDlog api
impl HDDlog {
    pub fn insert_transformer_data<T: Any + Send + Sync + 'static>(&self, value: T) -> Option<T> {
        self.transformer_data.insert(value)
    }
}

// Relation transformers, could be made opt-in by using an attribute on the transformer
pub fn MyTransformer(transformer_data: &TypeMap, ...) -> ... {
    let program_mode = transformer_data.get::<ProgramMode>().unwrap();

    match program_mode {
        ProgramMode::Lsp => { .. }
        ProgramMode::Cli => { .. }
    }
}

// Api usage
let (hddlog, _) = HDDlog::new(1, false).unwrap();
hddlog.insert_transformer_data(ProgramMode::Lsp);
ryzhyk commented 3 years ago

Why not introduce an extra input relation with a single record that represents program mode or any other metadata the transformer needs and pass this relation to the transformer. This way you can support this use case without making changes to the compiler.

mihaibudiu commented 3 years ago

How can you find out in DDlog whether you are in a CLI mode? Perhaps we can have a "system" relation that exposes such attributes. And an ENV relation that exposes (read-only) environment variables. etc.

ryzhyk commented 3 years ago

If you really need to know the mode while constructing the dataflow, why not just use a global variable that you can set from Rust and read in the transformer code?

Kixiron commented 3 years ago

Why not introduce an extra input relation with a single record that represents program mode or any other metadata the transformer needs and pass this relation to the transformer. This way you can support this use case without making changes to the compiler.

The values from the input relations won't exist until runtime (as opposed to dataflow construction time)

If you really need to know the mode while constructing the dataflow, why not just use a global variable that you can set from Rust and read in the transformer code?

Yes, this is an option, but global variables aren't very good and I'd prefer an alternative

How can you find out in DDlog whether you are in a CLI mode? Perhaps we can have a "system" relation that exposes such attributes. And an ENV relation that exposes (read-only) environment variables. etc.

For this in particular the idea is that the rest of the datalog code doesn't actually need to know anything, this is just an optimized implementation of the relation itself

ryzhyk commented 3 years ago

Yes, this is an option, but global variables aren't very good and I'd prefer an alternative

They might be the lesser evil in this case. Adding an ad hoc feature to the API seems even less pleasant to me. But if we go down this path we might need to merge the API refactoring PR first. It moves some of the definitions from the api module to differential_datalog, which may help.

ryzhyk commented 3 years ago

@Kixiron , any objections is I close this as wontfix? Or do you still think we need this feature?

Kixiron commented 3 years ago

Well, I opened it because I need the feature. Multiple of my projects involving ddlog are language-based ones that already have things like interners and arenas that are used throughout the rest of the program and make up much of the input data. Without being able to pass in interners and all that jazz I currently have to deserialize the data at the ddlog boundary and serialize it within ddlog (and vice versa for outputs), making it not ideal in a lot of ways

ryzhyk commented 3 years ago

Isn't that #804?

Kixiron commented 3 years ago

It's both, that one is for doing it in transformers and this one is for doing it in vanilla relations