PolicyFlow

Operators Reference

Complete guide to all operators in PolicyFlow

PolicyFlow provides a comprehensive set of operators for arithmetic, comparison, logical operations, and more. This reference covers all operators with examples and best practices.

Arithmetic Operators

Basic Arithmetic

OperatorNameDescriptionExample
+PlusAddition / Concatenation5 + 38
-MinusSubtraction10 - 46
*StarMultiplication6 * 742
/SlashDivision20 / 45
%ModuloRemainder17 % 52

Type-Specific Arithmetic

String Concatenation

const greeting = "Hello, " + user.name + "!";
const path = "/users/" + user.id + "/profile";

Temporal Arithmetic

// DateTime + Duration → DateTime
const deadline = DateTime.Now() + Duration.FromUnit(TimeUnit.Days, 7);

// DateTime - Duration → DateTime
const weekAgo = DateTime.Now() - Duration.FromUnit(TimeUnit.Days, 7);

// DateTime - DateTime → Duration
const age = DateTime.Now() - user.birthDate;
const ageInDays = age.TotalDays();

// Duration + Duration → Duration
const totalTime = duration1 + duration2;

Examples

rule CalculateDiscount {
    when {
        const basePrice = resource.price;
        const discountPercent = user.isPremium ? 20 : 5;
        const discount = basePrice * discountPercent / 100;
        const finalPrice = basePrice - discount;

        return finalPrice <= user.budget;
    }
    then ALLOW
}

rule CheckQuota {
    when {
        const used = user.storageUsed;
        const quota = user.storageQuota;
        const percentUsed = (used * 100) / quota;

        return percentUsed < 90;
    }
    then ALLOW
}

Comparison Operators

Equality and Inequality

OperatorNameDescriptionExample
==EqualValue equalityuser.id == resource.ownerId
!=Not EqualValue inequalityuser.status != "suspended"

Relational Operators

OperatorNameDescriptionExample
<Less ThanStrictly lessuser.age < 18
<=Less Than or EqualLess or equalscore <= 100
>Greater ThanStrictly greaterbalance > 0
>=Greater Than or EqualGreater or equallevel >= required

Type Comparisons

Different types have natural ordering:

  • Numbers: Mathematical ordering
  • Strings: Lexicographical ordering
  • DateTimes: Chronological ordering
rule CompareExamples {
    when {
        // Number comparison
        const hasBalance = user.balance > 0;

        // String comparison (lexicographical)
        const isLaterAlphabet = user.lastName > "M";

        // DateTime comparison
        const isExpired = resource.expiresAt < DateTime.Now();

        // Version comparison using strings
        const isNewVersion = resource.version >= "2.0.0";

        return hasBalance AND !isExpired;
    }
    then ALLOW
}

Logical Operators

Boolean Operators

OperatorAliasDescriptionExample
&&ANDLogical ANDisActive && isVerified
``OR
!NOTLogical NOT!user.isSuspended

Short-Circuit Evaluation

Logical operators use short-circuit evaluation:

rule ShortCircuitExample {
    when {
        // If user is null, the second condition is not evaluated
        if (user != null && user.isActive) {
            return true;
        }

        // If first condition is true, second is not evaluated
        if (user.isAdmin || expensiveCheck()) {
            return true;
        }

        return false;
    }
    then ALLOW
}

Complex Boolean Logic

rule ComplexLogic {
    when {
        const isAuthorized = (user.isActive AND user.emailVerified)
            OR user.isAdmin;

        const canAccess = isAuthorized
            AND (resource.isPublic OR user.id == resource.ownerId)
            AND NOT resource.isDeleted;

        return canAccess;
    }
    then ALLOW
}

Null-Safety Operators

Null-Safe Navigation (?.)

Safely access properties that might be null:

rule NullSafeAccess {
    when {
        // If user.manager is null, entire expression returns null
        const managerName = user.manager?.name;
        const managerDept = user.manager?.department?.name;

        // Chain multiple null-safe accesses
        const grandManagerId = user.manager?.manager?.id;

        // Safe with method calls
        const domain = user.manager?.email?.Domain();

        return managerDept == "Engineering";
    }
    then ALLOW
}

Null Coalescing (??)

Provide default values for null:

rule NullDefaults {
    when {
        // Use default if null
        const name = user.displayName ?? "Anonymous";
        const dept = user.department ?? "Unassigned";
        const level = user.clearanceLevel ?? 0;

        // Chain with null-safe navigation
        const managerEmail = user.manager?.email ?? "no-manager@company.com";

        // Multiple fallbacks
        const contactEmail = user.email ?? user.backupEmail ?? "support@company.com";

        return level >= resource.requiredLevel;
    }
    then ALLOW
}

Conditional Operator

Ternary Operator (? :)

Concise conditional expressions:

rule TernaryExamples {
    when {
        // Basic ternary
        const accessLevel = user.isAdmin ? "full" : "limited";

        // Nested ternary (use sparingly)
        const priority = resource.isCritical ? "high" :
                        resource.isImportant ? "medium" : "low";

        // With calculations
        const timeout = user.isPremium ? 3600 : 1800;
        const maxAttempts = user.isTrusted ? 10 : 3;

        // In conditions
        const canEdit = (user.role == "editor" ? true : user.id == resource.ownerId);

        return canEdit;
    }
    then ALLOW
}

Membership Operator

The in Operator

Check membership in collections:

rule MembershipChecks {
    when {
        // Array membership
        const hasAdminRole = "admin" in user.roles;
        const isWeekend = DateTime.Now().DayOfWeek() in [0, 6];

        // String contains (substring check)
        const isInternalEmail = "@company.com" in user.email;

        // Map key existence
        const hasAttribute = "clearanceLevel" in user.attributes;

        // Multiple values
        const hasAnyRole = user.role in ["admin", "editor", "moderator"];

        return hasAdminRole OR hasAnyRole;
    }
    then ALLOW
}

Operator Precedence

Operators are evaluated in this order (highest to lowest):

  1. Member Access: ., ?., ()
  2. Unary: !, - (negation)
  3. Multiplicative: *, /, %
  4. Additive: +, -
  5. Relational: <, <=, >, >=, in
  6. Equality: ==, !=
  7. Logical AND: &&, AND
  8. Logical OR: ||, OR
  9. Null Coalescing: ??
  10. Ternary: ? :

Precedence Examples

rule PrecedenceExamples {
    when {
        // Multiplication before addition
        const result1 = 2 + 3 * 4;  // 14, not 20

        // Comparison before logical
        const result2 = 5 > 3 && 2 < 4;  // true && true = true

        // Use parentheses for clarity
        const result3 = (user.score + bonus) * multiplier > threshold;

        // Complex expression
        const canAccess = user.isActive &&
            (user.role == "admin" || user.id == resource.ownerId) &&
            resource.status != "archived";

        return canAccess;
    }
    then ALLOW
}

Best Practices

1. Use Parentheses for Clarity

// Clear
const canEdit = (user.isOwner || user.isAdmin) && resource.isEditable;

// Unclear
const canEdit = user.isOwner || user.isAdmin && resource.isEditable;

2. Prefer Named Variables

// Good: Clear intent
const isOwner = user.id == resource.ownerId;
const hasPermission = "edit" in user.permissions;
const isEditable = !resource.isLocked && resource.status == "draft";

when isOwner && hasPermission && isEditable then ALLOW

// Less clear: Everything in one expression
when user.id == resource.ownerId && "edit" in user.permissions && !resource.isLocked && resource.status == "draft" then ALLOW

3. Use Appropriate Operators

// Use null-safe operators when needed
const dept = user.manager?.department ?? "Unknown";

// Use ternary for simple conditions
const limit = user.isPremium ? 1000 : 100;

// Use AND/OR aliases for readability in complex conditions
when user.isActive AND (user.hasSubscription OR user.isTrial) then ALLOW

4. Be Careful with Type Coercion

PolicyFlow is strongly typed and doesn't do implicit conversions:

// This will cause a compile error
when user.age > "18" then ALLOW  // Error: comparing Number to String

// Correct
when user.age > 18 then ALLOW

Next Steps