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

RFC: Opaque context in expression evaluation #75

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

TennyZhuang
Copy link
Contributor

@TennyZhuang TennyZhuang commented Sep 5, 2023

Signed-off-by: TennyZhuang <[email protected]>
Signed-off-by: TennyZhuang <[email protected]>

### task_local

tokio's [`task_local` macro](https://docs.rs/tokio/latest/tokio/macro.task_local.html) can achieve the same result even simpler, and the only cost is the extensive use of global variables.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

task_local is not that "global" as the calling stack or the scope of evaluating an expression tree is quite clear. I would vote for this approach as it introduces minimal changes to the codebase.

Copy link

@wangrunji0408 wangrunji0408 Sep 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for this approach. Adding context to the eval interface will make things more complicated and prevent easy use for most of the pure functions. Every time we call eval, we have to find out a context to pass in...

It's annoying to let developers pass context everywhere themselves. I once tried that in madsim, but soon gave it up and made the context global.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can even pass a () as context here. I don’t think it’s a heavy problem.

The key concept is pass it explicitly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can also add a eval_with_empty_context.

It’s really simple.

Copy link
Contributor Author

@TennyZhuang TennyZhuang Sep 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact, all eval needs a context and I'd prefer pass it explicitly instead of the one from an unknown scope.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another solution: is it possible to put the context into the expressions themselves? I've discussed it with @shanicky yesterday.

Not good. "The lifetime of the context will be longer".

Yes, my point is explicit context will put more burden on developers and make it error-prone

I think evaluating expression doesn't happen everywhere. For example, in backend, it should only happen in a few executors: Project and Join (for inner join condition). Passing an explicit context helps to make it less error pruning.

On the other hand, if a developer does need to eval in some strange place, get_context will return None and the evaluation should act in default behavior (such as with UTC+0 timezone). The missing context (like Context::empty()) always warns him about this behavior, as long as he takes the risk, he can do it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Besides, from my understanding, @TennyZhuang's point to introduce provide instead of using a simple struct ExprContext is he wants to make it more flexible. For example, if BackendContext exists, then the eval() function can get it; otherwise, it gets None. So if you are sure that no context is needed somewhere (I don't know what can be the case... but just saying), it's possible to use an empty context.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but we need to move the expression construction out of the expr crate.

Not necessary? We can pass the opaque context into the constructor function.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think evaluating expression doesn't happen everywhere.

It does happen everywhere in unit tests. And we have to provide an empty context for each of them. However, I think providing a eval_with_default_context method is acceptable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does happen everywhere in unit tests.

Well. Indeed. 😄

If it costs too many changes to replace eval to eval_with_default_context, scoped task_local might look a little bit better. Either way LGTM.

By the way, it's worth mentioning that using provide or not is orthogonal to whether to put context in function call arguments or task_local: you may also put the Context: Provider as a task-local variable.

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

Successfully merging this pull request may close these issues.

4 participants