Skip to content

Feature: Conditional Evaluation via Inlining #13

@WalkerCodeRanger

Description

@WalkerCodeRanger

Consider a function like:

public static class BoolExtensions
{
    /// <summary>
    /// The logical relation implies (i.e. X implies Y means that if X is true then Y must be true).
    /// </summary>
    [Inline(export: true)]
    public static bool Implies(this bool self, bool other) => !self || other;
}

It would be great if there was a way to make this boolean connective short-circuiting. With a couple of additional features to inlining, it would be!

Option A

First, the inlining would need to optimize away lambdas and/or expression trees. That is, InlineMethod.Fody should guarantee that when the below methods are inlined, a lambda parameter should be inlined out of existence while preserving the semantics.

    [Inline(export: true)]
    public static bool Implies(this bool self, Func<bool> other) => !self || other();

    [Inline(export: true)]
    public static bool Implies(this bool self, Expression<Func<bool>> other) => !self || other.Compile()();

That provides short-circuiting. But if this were called from a project that didn't have InlineMethod.Fody properly installed, then the original method would be called, introducing the overhead of the lambda. We can't use [Inline(InlineBehavior.Remove, export: true)] because then the method is missing when we try to compile projects dependent on it. Unfortunately, I can't think of a way to enforce this at compile time. But, an option could be added like InlineBehavior.Throw, which would replace the body of the method with throw InvalidOperationException(). That way the mistake would be found at runtime.

Option B

In some ways this is cleaner, but it makes the function more magical to call. An additional attribute could be added to the package to mark parameters that should be treated this way, even without lambdas. In programming language terms, this is "call by need." So it would be something like:

    [Inline(export: true)]
    public static bool Implies(this bool self, [CallByNeed] bool other) => !self || other();

And that could be called just like any other method (e.g. a.Implies(b)) but would then be short-circuiting when inlined. Something like InlineBehavior.Throw would still be needed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions