bool BasicComparison::compareTypeInstancesCheckedHelper(const TypeInstance &left, const TypeInstance &right) const {
  if (!canCompareTypes(left.getType(), right.getType())) {
    throw OperationInapplicableToType(*this, 2, &left.getType(), &right.getType());
  }

  if (left.isNull() || right.isNull()) {
    return false;
  }

  if (left.getType().getSuperTypeID() == Type::kAsciiString) {
    ComparisonFunctor<int> comparison_functor;
    return comparison_functor(strcmpHelper(left, right), 0);
  } else {
    const Type *unifier = Type::GetUnifyingType(left.getType(), right.getType());
    DEBUG_ASSERT(unifier != NULL);

    switch (unifier->getTypeID()) {
      case Type::kInt: {
        DEBUG_ASSERT(left.supportsNumericInterface());
        DEBUG_ASSERT(right.supportsNumericInterface());
        ComparisonFunctor<int> comparison_functor;
        return comparison_functor(left.numericGetIntValue(), right.numericGetIntValue());
      }
      case Type::kLong: {
        DEBUG_ASSERT(left.supportsNumericInterface());
        DEBUG_ASSERT(right.supportsNumericInterface());
        ComparisonFunctor<int64_t> comparison_functor;
        return comparison_functor(left.numericGetLongValue(), right.numericGetLongValue());
      }
      case Type::kFloat: {
        DEBUG_ASSERT(left.supportsNumericInterface());
        DEBUG_ASSERT(right.supportsNumericInterface());
        ComparisonFunctor<float> comparison_functor;
        return comparison_functor(left.numericGetFloatValue(), right.numericGetFloatValue());
      }
      case Type::kDouble: {
        DEBUG_ASSERT(left.supportsNumericInterface());
        DEBUG_ASSERT(right.supportsNumericInterface());
        ComparisonFunctor<double> comparison_functor;
        return comparison_functor(left.numericGetDoubleValue(), right.numericGetDoubleValue());
      }
      default:
        throw OperationInapplicableToType(*this, 2, &left.getType(), &right.getType());
    }
  }
}
UncheckedComparator* BasicComparison::makeUncheckedComparatorForTypesHelper(const Type &left,
                                                                            const Type &right) const {
  if (!canCompareTypes(left, right)) {
    throw OperationInapplicableToType(*this, 2, &left, &right);
  }

  if (left.getSuperTypeID() == Type::kAsciiString) {
    return makeStringComparatorOuterHelper<StringComparator>(*this, left, right);
  } else {
    return makeComparatorOuterHelper<NumericComparator>(*this, left, right);
  }
}
void ScalarUnaryExpression::initHelper(bool own_children) {
  if (operation_.canApplyToType(operand_->getType())) {
    if (operand_->hasStaticValue()) {
      static_value_ = operation_.applyToChecked(operand_->getStaticValue(),
                                                operand_->getType());
    } else {
      fast_operator_.reset(operation_.makeUncheckedUnaryOperatorForType(operand_->getType()));
    }
  } else {
    const Type &operand_type = operand_->getType();
    if (!own_children) {
      operand_.release();
    }
    throw OperationInapplicableToType(operation_.getName(), 1, operand_type.getName().c_str());
  }
}
void ComparisonPredicate::initHelper(bool own_children) {
  if (comparison_.canCompareTypes(left_operand_->getType(), right_operand_->getType())) {
    if (left_operand_->hasStaticValue() && right_operand_->hasStaticValue()) {
      static_result_ = comparison_.compareTypedValuesChecked(left_operand_->getStaticValue(),
                                                             left_operand_->getType(),
                                                             right_operand_->getStaticValue(),
                                                             right_operand_->getType());
    } else {
      fast_comparator_.reset(comparison_.makeUncheckedComparatorForTypes(left_operand_->getType(),
                                                                         right_operand_->getType()));
    }
  } else {
    const Type &left_operand_type = left_operand_->getType();
    const Type &right_operand_type = right_operand_->getType();
    if (!own_children) {
      left_operand_.release();
      right_operand_.release();
    }
    throw OperationInapplicableToType(comparison_.getName(),
                                      2,
                                      left_operand_type.getName().c_str(),
                                      right_operand_type.getName().c_str());
  }
}