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

Short-circuiting || and && #3492

Merged
merged 14 commits into from
Jun 2, 2022

Conversation

hubertp
Copy link
Contributor

@hubertp hubertp commented May 27, 2022

Pull Request Description

Short-circuiting || and && is typically taken for granted
by users of other PLs. This change makes it happen for Enso.

Related to https://www.pivotaltracker.com/story/show/182261401

Checklist

Please include the following checklist in your PR:

  • The documentation has been updated if necessary.
  • All code conforms to the
    Scala,
    Java,
    and
    Rust
    style guides.
  • All code has been tested:
    • Unit tests have been written where possible.
    • If GUI codebase was changed: Enso GUI was tested when built using BOTH
      ./run.sh ide dist and ./run.sh ide watch.

@hubertp hubertp changed the title Don't evaluate RHS of || and && eagerly Lazy evaluation of RHS argument for || and && May 27, 2022
Copy link
Member

@JaroslavTulach JaroslavTulach left a comment

Choose a reason for hiding this comment

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

I have to admit I cannot imagine how these changes reflect in the shape of our IGV graphs. It is certainly desirable to verify things like instanceof DataflowError or makeTypeError don't appear in graphs that are trained just with Boolean.

@hubertp hubertp marked this pull request as draft May 28, 2022 22:40
@hubertp hubertp force-pushed the wip/hubert/short-circuit-bool-ops-182261401 branch 2 times, most recently from 7ef43d7 to 4fb0842 Compare May 29, 2022 10:05
@hubertp hubertp marked this pull request as ready for review May 30, 2022 15:18
@hubertp hubertp force-pushed the wip/hubert/short-circuit-bool-ops-182261401 branch from fdb2c0e to caaa5bf Compare May 31, 2022 16:35
Lazy evaluation of RHS for || and && is typically taken for granted
by users of other PLs. This change makes it happen for Enso.
Pushed lhs guard check inside the specialization so as to prevent
potentially continuous flipping between optimized and deoptimized
version, depending on the LHS value.
Simple benchmarks showed 10x improvement compared to the previous
solution.
Rather than using multiple specializations in AndNode/OrNode and various
instance checks, it seems Truffle is able to better optimize potential
DataflowError/Panic by delegating to a separate Node. Benchmarks also
appear to be happier that way.
@hubertp hubertp force-pushed the wip/hubert/short-circuit-bool-ops-182261401 branch from 4cf6665 to 73716eb Compare June 2, 2022 08:15
@Suspend Object that,
@Cached("build()") ThunkExecutorNode rhsThunkExecutorNode,
@Cached("build()") ToBoolNode ensureBoolNode) {
if (!_this) {
Copy link
Contributor

Choose a reason for hiding this comment

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

To make sure the compiler really understands this method, use a profile for this condition.

return new Stateful(state, false);
}
Stateful result =
rhsThunkExecutorNode.executeThunk(that, state, BaseNode.TailStatus.TAIL_DIRECT);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not a TAIL_DIRECT, it's a NON_TAIL. TAIL_DIRECT is not guaranteed to return in this method (may unwind)

Copy link
Contributor

Choose a reason for hiding this comment

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

OTOH I wonder if we really want that type check? Given we don't actually depend on the expression evaluating to bool? Why not just return the result of executeThunk?

return ToBoolNodeGen.create();
}

abstract Stateful execute(@MonadicState Object state, Object value);
Copy link
Contributor

Choose a reason for hiding this comment

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

This should not return a Stateful, it's not the node's responsibility – the point of this node is "make sure my arg is a bool", so just return a boolean.

import org.enso.interpreter.runtime.state.Stateful;

@NodeInfo(description = "Helper node to handle Bool values that can also return DataflowErrors")
public abstract class ToBoolNode extends Node {
Copy link
Contributor

Choose a reason for hiding this comment

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

A convention we use is to call such throwing conversions ExpectBoolNode. ToBoolNode suggests you can convert anything.

Copy link
Contributor

@kustosz kustosz left a comment

Choose a reason for hiding this comment

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

Was to quick to submit the previous review – so here comes the prose. The more I think about the result casting, the less I like it. I'd just allow any return type and not verify it. It's like if you implemented these in Enso:

Boolean.|| ~that = if this then this else that

You wouldn't check the result type in this impl, and I think we should follow this thinking here.

@hubertp
Copy link
Contributor Author

hubertp commented Jun 2, 2022

Was to quick to submit the previous review – so here comes the prose. The more I think about the result casting, the less I like it. I'd just allow any return type and not verify it. It's like if you implemented these in Enso:

Boolean.|| ~that = if this then this else that

You wouldn't check the result type in this impl, and I think we should follow this thinking here.

In that case the type of || should be changed from Boolean -> Boolean to Any -> Any. And that sounds a bit counter-intuitive given the actual method description.
e.g., False || 42 would return 42 rather than a runtime exception and that would be completely fine.

@hubertp hubertp changed the title Lazy evaluation of RHS argument for || and && Short circuiting || and && Jun 2, 2022
@hubertp hubertp changed the title Short circuiting || and && Short-circuiting || and && Jun 2, 2022
@kustosz
Copy link
Contributor

kustosz commented Jun 2, 2022

No, we should leave the type as is – it is normal for a type signature to be more restrictive than the implementation :)

@hubertp hubertp requested a review from kustosz June 2, 2022 10:17
@hubertp
Copy link
Contributor Author

hubertp commented Jun 2, 2022

@kustosz as discussed

@hubertp hubertp force-pushed the wip/hubert/short-circuit-bool-ops-182261401 branch from 02f707e to 651ea32 Compare June 2, 2022 10:31
Copy link
Contributor

@kustosz kustosz left a comment

Choose a reason for hiding this comment

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

There's more simplification to do :)

@hubertp hubertp requested a review from kustosz June 2, 2022 12:08
@hubertp hubertp added the CI: Ready to merge This PR is eligible for automatic merge label Jun 2, 2022
@mergify mergify bot merged commit e43325b into develop Jun 2, 2022
@mergify mergify bot deleted the wip/hubert/short-circuit-bool-ops-182261401 branch June 2, 2022 16:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI: Ready to merge This PR is eligible for automatic merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants