For example, if I use UInt8 constant for if condition then only one branch is evaluated:
```sql
SELECT if(1, 'success', throwIf(1, 'Executing FALSE branch'))

┌─'success'─┐
│ success   │
└───────────┘

1 rows in set. Elapsed: 0.003 sec.
```

But if I use some constant expression, then both branches are evaluated:
```sql
SELECT if(empty(''), 'success', throwIf(1, 'Executing FALSE branch'))

0 rows in set. Elapsed: 0.003 sec.

Received exception from server (version 21.12.2):
Code: 395. DB::Exception: Received from localhost:9000. DB::Exception: Executing FALSE branch: While processing if(empty(''), 'success', throwIf(1, 'Executing FALSE branch')). (FUNCTION_THROW_IF_VALUE_IS_NON_ZERO)
```
const ColumnsWithTypeAndName & args, const DataTypePtr & result_type, size_t input_rows_count) const
{
    ColumnsWithTypeAndName arguments = std::move(args);
    
    if (checkShirtCircuitArguments(arguments) != -1)
        return executeShortCircuit(arguments, result_type);
    ColumnRawPtrs args_in;
    for (const auto & arg_index : arguments)
        args_in.push_back(arg_index.column.get());
    if (result_type->isNullable())
        return executeForTernaryLogicImpl<Impl>(std::move(args_in), result_type, input_rows_count);
    else
        return basicExecuteImpl<Impl>(std::move(args_in), input_rows_count);
}
template <typename Impl, typename Name>
ColumnPtr FunctionAnyArityLogical<Impl, Name>::getConstantResultForNonConstArguments(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type) const