4

I'm trying to find the simplest way to model user-defined conditional statements without resorting to text parsing. This is fairly easy when there is only one condition in the statement because you can split that into an operand, a comparison operator, and a value to compare with. Just store those three and you can let the user use dropdown boxes to select values and an operator from a predefined list.

In this example imagine the code snippet text is a dropdown box and bold text is uneditable:

IF (select value) is (select comparison operator) (enter value) then...

Clarification - so the bit between IF and IS is a dropdown box with an object's member or database field in, the comparison operator is a dropdown box with options such as "equal to" or "greater than", and the final box is a typeable text box where the user can enter the value manually.

But occasionally they will need to test multiple conditions before executing whatever action they define. Microsoft Dynamics CRM does this quite well with their business rules (which is similar to what I am trying to achieve) as you can see here.

In simple examples, you can rearrange it into nested if statements, although you may end up repeating yourself if using a lot of ORs. It's not the prettiest solution in the world but at the end of the day it works and you don't run the risk of allowing the user to type badly formed input. I anticipate complex multiple conditional logic to be an edge case for this project so the messiness is (mostly) justified.

The million dollar question is are there any cases where conditional logic cannot be represented like this?

EDIT in order to explain how this question is not a duplicate of this one, that question is not (as far as I can tell) asking the same thing. Although both questions deal with evaluating unknown variations of Boolean expressions, I am asking if my solution will allow me to represent all feasible expressions with a particular method, while that question is asking about unit testing for Boolean expressions with many inputs.

leylandski
  • 407
  • 1
  • 3
  • 14
  • You need `(select value)` to be `((select value 1) AND (select value 2))`? –  Oct 28 '15 at 16:07
  • Not quite, I need **if** `(a)` **and** `(b)` to become **if** `(a)` **then... if** `(b)` **then...**. It's long winded and inefficient but in this case it means the user doesn't have to understand the syntax of the statement, they can just pick values. What I want to know though is can this principle be employed for all conditional logic or is there a case that cannot be done like this? – leylandski Oct 28 '15 at 16:11
  • @leylandski Many rule engines allow a if/then rule to have multiple conditionals that can be combined: `if all of … and … and … then …` or `if any of … or … or … then …`. This is fairly simple to understand since the complexity of a rule condition is limited – the language need not be recursive. Note that nesting conditionals is equivalent to `and`, but multiple separate conditionals with the same body would be equivalent to `or`. That becomes really unwieldy very fast, so I'd recommend against this wrong kind of minimalism. – amon Oct 28 '15 at 16:36
  • I have a similar solution for validation rules with a conditional logic parser/evaluator (`(1 OR 2) AND 3`) but I was hoping I wouldn't have to revisit that code for a while :/ – leylandski Oct 28 '15 at 16:38
  • Can you create a new value to test with the next line? – ratchet freak Oct 28 '15 at 16:44
  • Not sure what you mean when you say to create a new value. I've added clarification but each business rule (stealing terminology from MS Dynamics) can have as many IF statements as the user defines, and they can be executed sequentially or can be nested. – leylandski Oct 28 '15 at 16:50
  • 1
    Possible duplicate of [How should I test boolean function with many possible permutations](http://programmers.stackexchange.com/questions/246226/how-should-i-test-boolean-function-with-many-possible-permutations) – gnat Oct 28 '15 at 17:18
  • Edited to explain difference. – leylandski Oct 28 '15 at 17:25

1 Answers1

6

Nested conditions along the lines of ((foo or bar) and baz) are hard to comprehend, and I understand that you want to avoid them. Indeed, you can avoid the logical operators and, or and not if you allow conditionals to be nested:

  • if (foo and bar) then action is equivalent to

    if (foo) then
      if (bar) then
        action
    
  • if (foo or bar) then action is equivalent to

    if (foo) then
      action
    otherwise
      if (bar) then
        action
    
  • if (not foo) then action is equivalent to

    if (foo) then
      nothing
    otherwise
      action
    
  • if ((foo or bar) and baz) then action is equivalent to

    if (foo) then
      if (baz) then
        action
    otherwise
      if (bar) then
        if (baz) then
          action
    

    or

    if (baz) then
      if (foo) then
        action
      otherwise
        if (bar) then
          action
    

This isn't exactly easy to understand either, and requires a lot of repetition.

It might be much simpler to allow one if … then … to have multiple conditions that can be combined via any of, all of and none of quantifiers (these correspond to the mathematical quantifiers ∃ there exists, ∀ for all, and ∄ there does not exist). This is easy to introduce into a form-based interface, and drastically increases power and usability of your rules. However, they are not quite as powerful as arbitrarily-nested conditions. This can be resolved by introducing user-defined variables or virtual fields. With variables, sub-conditions can be combined, named, and re-used.

Using these two improvements, a conditional if ((foo or bar) and baz) then action might become

yes/no field foo-or-bar
  is any of foo
         or bar

if all of foo-or-bar
      and baz
then
  action

where foo, bar, baz are arbitrary atomic conditions. This achieves the same expressivity as nested condition expressions, without requiring users to repeat their conditions and actions.

amon
  • 132,749
  • 27
  • 279
  • 375
  • Definitely something to think about. I can eliminate the use of **not** by having "not equal to" as a comparison operand. I plan on making my conditional logic parser/evaluator public on GitHub soon so this could be something to add in to make it a bit more general purpose. – leylandski Oct 28 '15 at 17:16
  • 2
    "if (foo or bar) then action" is not equivalent to if (foo) then action if (bar) then action. If both foo and bar are true the your example calls action twice. – Dunk Oct 28 '15 at 21:14
  • @Dunk you're absolutely right – I just edited the question to correct that. – amon Oct 28 '15 at 21:18