diff --git a/libwccl/ops/conditional.h b/libwccl/ops/conditional.h
new file mode 100644
index 0000000000000000000000000000000000000000..e17a02042984bdab552cf27c4f8cfb515720d920
--- /dev/null
+++ b/libwccl/ops/conditional.h
@@ -0,0 +1,148 @@
+#ifndef CONDITIONAL_H
+#define CONDITIONAL_H
+
+#include <boost/shared_ptr.hpp>
+#include <boost/mpl/list.hpp>
+#include <boost/mpl/assert.hpp>
+#include <boost/mpl/count.hpp>
+#include <libwccl/ops/predicate.h>
+#include <libwccl/ops/formatters.h>
+#include <libwccl/ops/constant.h>
+
+namespace Wccl {
+
+/**
+ * Template class for conditional operators, returning value
+ * depending on evaluation of some predicate.
+ * This class is targeted towards if..then..else expression
+ */
+template<class T>
+class Conditional : public Function<T> {
+public:
+	typedef boost::shared_ptr<Function<T> > ArgFunctionPtr;
+	typedef boost::shared_ptr<Function<Bool> > BoolFunctionPtr;
+
+	Conditional(
+		const BoolFunctionPtr& cond_expr,
+		const ArgFunctionPtr& iftrue_expr,
+		const ArgFunctionPtr& iffalse_expr = ArgFunctionPtr(new Constant<T>(T())))
+		: cond_expr_(cond_expr), iftrue_expr_(iftrue_expr), iffalse_expr_(iffalse_expr)
+	{
+		BOOST_ASSERT(cond_expr_);
+		BOOST_ASSERT(iftrue_expr_);
+		BOOST_ASSERT(iffalse_expr_);
+	}
+
+	/**
+	 * String representation of conditional operator in form of:
+	 * "if cond_expr_string then iftrue_expr_string else iffalse_expr_string"
+	 */
+	virtual std::string to_string(const Corpus2::Tagset& tagset) const {
+		std::string s(this->operator_name(tagset));
+		s.append(" ");
+		s.append(cond_expr_->to_string(tagset));
+		s.append(" then ");
+		s.append(iftrue_expr_->to_string(tagset));
+		s.append(" else ");
+		s.append(iffalse_expr_->to_string(tagset));
+		return s;
+	}
+
+	/**
+	 * String representation of conditional operator in form of:
+	 * "if cond_expr_raw_s then iftrue_expr_raw_s else iffalse_expr_raw_s"
+	 * This version does not require tagset, but may be inclomplete
+	 * and/or contain internal info.
+	 */
+	virtual std::string to_raw_string() const {
+		std::string s(this->raw_operator_name());
+		s.append(" ");
+		s.append(cond_expr_->to_raw_string());
+		s.append(" then ");
+		s.append(iftrue_expr_->to_raw_string());
+		s.append(" else ");
+		s.append(iffalse_expr_->to_raw_string());
+		return s;
+	}
+
+	virtual const std::string raw_operator_name() const {
+		return "if";
+	}
+
+protected:
+	const BoolFunctionPtr cond_expr_;
+	const ArgFunctionPtr iftrue_expr_;
+	const ArgFunctionPtr iffalse_expr_;
+
+	typedef FunctionBase::BaseRetValPtr BaseRetValPtr;
+
+	/**
+	 * Evaluate the predicate. If it is true, evaluate and return value of
+	 * iftrue_expression. If predicate is false, evalute and return value
+	 * of iffalse_expression.
+	 */
+	virtual BaseRetValPtr apply_internal(const SentenceContext& context) const {
+		if(this->cond_expr_->apply(context)->get_value()) {
+			return iftrue_expr_->apply(context);
+		}
+		return iffalse_expr_->apply(context);
+	}
+};
+
+/**
+ * Template class for conditional operator targeted
+ * towards the operator "? if_true_value ? predicate"
+ * Difference between base Conditional<T> is that
+ * the if_false_value is always default,
+ * and string representation is different.
+ */
+template<class T>
+class ConditionalOp : public Conditional<T> {
+public:
+	typedef typename Conditional<T>::ArgFunctionPtr ArgFunctionPtr;
+	typedef boost::shared_ptr<Function<Bool> > BoolFunctionPtr;
+
+	ConditionalOp(
+		const BoolFunctionPtr& cond_expr,
+		const ArgFunctionPtr& iftrue_expr)
+		: Conditional<T>(cond_expr, iftrue_expr)
+	{
+	}
+
+	/**
+	 * String representation of conditional operator in form of:
+	 * "? if_true_expr_string ? cond_expr_string"
+	 */
+	virtual std::string to_string(const Corpus2::Tagset& tagset) const {
+		std::string s(this->operator_name(tagset));
+		s.append(" ");
+		s.append(this->iftrue_expr_->to_string(tagset));
+		s.append(" ? ");
+		s.append(this->cond_expr_->to_string(tagset));
+		return s;
+	}
+
+	/**
+	 * String representation of conditional operator in form of:
+	 * "? if_true_expr_raw_string ? cond_expr_raw_string"
+	 * This version does not require tagset, but may be inclomplete
+	 * and/or contain internal info.
+	 */
+	virtual std::string to_raw_string() const {
+		std::string s(this->raw_operator_name());
+		s.append(" ");
+		s.append(this->iftrue_expr_->to_raw_string());
+		s.append(" ? ");
+		s.append(this->cond_expr_->to_raw_string());
+		return s;
+	}
+
+	virtual const std::string raw_operator_name() const {
+		return "?";
+	}
+};
+
+
+} /* end ns Wccl */
+
+#endif // CONDITIONAL_H
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 58d9f29202424e079da5495c35ea93dfc07a45c9..abc70b5fedb3e992ca07971fb536ae844b2b4bbb 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -5,6 +5,7 @@ include_directories( ${CMAKE_SOURCE_DIR} )
 add_definitions(-DLIBWCCL_TEST_DATA_DIR="${PROJECT_SOURCE_DIR}/")
 
 add_executable(tests
+	conditional.cpp
 	constant_tests.cpp
 	context.cpp
 	logicalpredicates.cpp
diff --git a/tests/conditional.cpp b/tests/conditional.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6693301bf49022ed79a6c4c49bfd619ab843a262
--- /dev/null
+++ b/tests/conditional.cpp
@@ -0,0 +1,151 @@
+#include <boost/test/unit_test.hpp>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <libcorpus2/sentence.h>
+
+#include <libwccl/ops/constant.h>
+#include <libwccl/ops/conditional.h>
+
+#include <libwccl/values/bool.h>
+#include <libwccl/values/tset.h>
+#include <libwccl/values/strset.h>
+
+#include <libwccl/sentencecontext.h>
+
+using namespace Wccl;
+
+BOOST_AUTO_TEST_SUITE(logical_predicates)
+
+struct CondFix
+{
+	CondFix()
+		: sc(boost::make_shared<Corpus2::Sentence>()),
+		  tagset(),
+		  true_value(true),
+		  false_value(false),
+		  true_constant(new Constant<Bool>(true_value)),
+		  false_constant(new Constant<Bool>(false_value))
+	{		
+	}
+	SentenceContext sc;
+	Corpus2::Tagset tagset;
+
+	Bool true_value;
+	Bool false_value;
+	Conditional<StrSet>::BoolFunctionPtr true_constant;
+	Conditional<StrSet>::BoolFunctionPtr false_constant;
+};
+
+struct CondFixStrSet : public CondFix
+{
+	CondFixStrSet()
+	: CondFix(),
+		iftrue_strset(),
+		iffalse_strset(),
+		empty_strset(),
+		one_elem_strset()
+	{
+		iftrue_strset.insert("I");
+		iftrue_strset.insert("am");
+		iftrue_strset.insert("True");
+		iftrue_strset_expr = Conditional<StrSet>::ArgFunctionPtr(new Constant<StrSet>(iftrue_strset));
+		iffalse_strset.insert("I");
+		iffalse_strset.insert("am");
+		iffalse_strset.insert("so");
+		iffalse_strset.insert("False");
+		iffalse_strset_expr = Conditional<StrSet>::ArgFunctionPtr(new Constant<StrSet>(iffalse_strset));
+		one_elem_strset.insert("oNe");
+		one_elem_strset_expr = Conditional<StrSet>::ArgFunctionPtr(new Constant<StrSet>(one_elem_strset));
+		empty_strset_expr = Conditional<StrSet>::ArgFunctionPtr(new Constant<StrSet>(empty_strset));
+	}
+
+	StrSet iftrue_strset;
+	StrSet iffalse_strset;
+	StrSet empty_strset;
+	StrSet one_elem_strset;
+	Conditional<StrSet>::ArgFunctionPtr iftrue_strset_expr;
+	Conditional<StrSet>::ArgFunctionPtr iffalse_strset_expr;
+	Conditional<StrSet>::ArgFunctionPtr empty_strset_expr;
+	Conditional<StrSet>::ArgFunctionPtr one_elem_strset_expr;
+};
+
+BOOST_FIXTURE_TEST_CASE(true_condition_strset, CondFixStrSet)
+{
+	BOOST_CHECK(!iftrue_strset.equals(iffalse_strset));
+
+	boost::shared_ptr<Conditional<StrSet> > cond(new Conditional<StrSet>(
+		true_constant,
+		iftrue_strset_expr,
+		iffalse_strset_expr));
+
+	BOOST_CHECK(iftrue_strset.equals(*(cond->apply(sc))));
+}
+
+BOOST_FIXTURE_TEST_CASE(false_condition_strset, CondFixStrSet)
+{
+	boost::shared_ptr<Conditional<StrSet> > cond(new Conditional<StrSet>(
+			false_constant,
+			iftrue_strset_expr,
+			iffalse_strset_expr));
+
+	BOOST_CHECK(iffalse_strset.equals(*(cond->apply(sc))));
+}
+
+BOOST_FIXTURE_TEST_CASE(true_condition_op_strset, CondFixStrSet)
+{
+	boost::shared_ptr<ConditionalOp<StrSet> > cond(new ConditionalOp<StrSet>(
+		true_constant,
+		iftrue_strset_expr));
+
+	BOOST_CHECK(iftrue_strset.equals(*(cond->apply(sc))));
+}
+
+BOOST_FIXTURE_TEST_CASE(false_condition_op_strset, CondFixStrSet)
+{
+	boost::shared_ptr<ConditionalOp<StrSet> > cond(new ConditionalOp<StrSet>(
+			false_constant,
+			iftrue_strset_expr));
+
+	BOOST_CHECK(empty_strset.equals(*(cond->apply(sc))));
+}
+
+//------ to_string test cases -------
+
+BOOST_FIXTURE_TEST_CASE(cond_to_string, CondFixStrSet)
+{
+	boost::shared_ptr<Conditional<StrSet> > cond(new Conditional<StrSet>(
+		true_constant,
+		empty_strset_expr,
+		one_elem_strset_expr));
+	std::string expected = "if True then [] else [\"oNe\"]";
+	BOOST_CHECK_EQUAL(expected, cond->to_string(tagset));
+}
+
+BOOST_FIXTURE_TEST_CASE(cond_to_string_raw, CondFixStrSet)
+{
+	boost::shared_ptr<Conditional<StrSet> > cond(new Conditional<StrSet>(
+		true_constant,
+		one_elem_strset_expr));
+	std::string expected = "if True then [\"oNe\"] else []";
+	BOOST_CHECK_EQUAL(expected, cond->to_string(tagset));
+}
+
+BOOST_FIXTURE_TEST_CASE(cond_op_to_string, CondFixStrSet)
+{
+	boost::shared_ptr<ConditionalOp<StrSet> > cond(new ConditionalOp<StrSet>(
+		true_constant,
+		empty_strset_expr));
+	std::string expected = "? [] ? True";
+	BOOST_CHECK_EQUAL(expected, cond->to_string(tagset));
+}
+
+BOOST_FIXTURE_TEST_CASE(cond_op_to_string_raw, CondFixStrSet)
+{
+	boost::shared_ptr<ConditionalOp<StrSet> > cond(new ConditionalOp<StrSet>(
+		false_constant,
+		one_elem_strset_expr));
+	std::string expected = "? [\"oNe\"] ? False";
+	BOOST_CHECK_EQUAL(expected, cond->to_string(tagset));
+}
+
+BOOST_AUTO_TEST_SUITE_END()