diff --git a/libwccl/values/position.cpp b/libwccl/values/position.cpp
index 5be0a85b2be1d03e3b48cbad9ff35801e4302899..f1cadf25c45e8b9dece29211949bece6fd09caaa 100644
--- a/libwccl/values/position.cpp
+++ b/libwccl/values/position.cpp
@@ -43,4 +43,9 @@ bool Position::is_inside(const SentenceContext& context) const
 	return context.is_inside(abs_position);
 }
 
+bool Position::equals(const Position& other, const SentenceContext& context) const
+{
+	return context.get_abs_position(*this) == context.get_abs_position(other);
+}
+
 } /* end ns Wccl */
diff --git a/libwccl/values/position.h b/libwccl/values/position.h
index fed7a414ed5369acf13a6c909b4e714db93ef26d..ca3f7a1e790df02833add568363d34d2f514a843 100644
--- a/libwccl/values/position.h
+++ b/libwccl/values/position.h
@@ -50,7 +50,8 @@ public:
 	/**
 	 * @returns True if underlying position values are equal, false otherwise.
 	 * @note This version does not take into account sentence context, only
-	 * the raw value of position.
+	 * the raw value of position. In practice it means that the special positions
+	 * Begin, End, Nowhere are equal only to a coresponding special position.
 	 */
 	bool equals(const Position& other) const {
 		return val_ == other.val_;
@@ -58,13 +59,13 @@ public:
 
 	/**
 	 * @returns True if positions are equal in context of a sentence, false otherwise.
-	 * @note This version determines if position values point outside of a sentence,
-	 * and if both of them do, they are considered to be equal as well (both "nowhere").
+	 * @note The equality is determined by absolute value of the Position in context
+	 * of a sentence (this means pointing to the same absolute position regardless
+	 * if it lies inside or outside of the sentence).
+	 * Nowhere is only equal to another Nowhere, but Begin or End may be equal to
+	 * a nonspecial position depending on the value of current position in the context.
 	 */
-	bool equals(const Position& other, const SentenceContext& context) const
-	{
-		return equals(other) || (is_outside(context) && other.is_outside(context));
-	}
+	bool equals(const Position& other, const SentenceContext& context) const;
 
 private:
 	int val_;
diff --git a/tests/values.cpp b/tests/values.cpp
index c39115e7cbbe63ea41660a8b1843e762c7d46c56..6f9e5c391c56d3a61c65d43ab741d7748aa0fce8 100644
--- a/tests/values.cpp
+++ b/tests/values.cpp
@@ -2,6 +2,7 @@
 #include <boost/bind.hpp>
 #include <libcorpus2/tagsetmanager.h>
 
+#include <libwccl/sentencecontext.h>
 #include <libwccl/variables.h>
 
 #include <iostream>
@@ -26,6 +27,14 @@ BOOST_AUTO_TEST_CASE(tsetz)
 	BOOST_CHECK_EQUAL(v.get_type_name(), TSet::type_name);
 }
 
+BOOST_AUTO_TEST_CASE(positionz)
+{
+	Position p;
+	BOOST_CHECK(p.get_value() == Position::Nowhere);
+	Value& v = p;
+	BOOST_CHECK_EQUAL(v.get_type_name(), Position::type_name);
+}
+
 BOOST_AUTO_TEST_CASE(strset_ops)
 {
 	StrSet s1, s2;
@@ -85,4 +94,67 @@ BOOST_AUTO_TEST_CASE(tset_ops)
 	BOOST_CHECK(s1.intersects(s2));
 }
 
+BOOST_AUTO_TEST_CASE(position_ops)
+{
+	boost::shared_ptr<Corpus2::Sentence> s(boost::make_shared<Corpus2::Sentence>());
+	SentenceContext sc(s);
+	Corpus2::Token* a_token = new Corpus2::Token("ZZ", PwrNlp::Whitespace::ManySpaces);
+	Corpus2::Tag t1(Corpus2::mask_t(0));
+	Corpus2::Lexeme l1("aaa", t1);
+	Corpus2::Lexeme l2("bbb", t1);
+	a_token->add_lexeme(l1);
+	a_token->add_lexeme(l2);
+	s->append(a_token);
+	s->append(a_token->clone());
+	Position begin(Position::Begin);
+	Position end(Position::End);
+	Position nowhere(Position::Nowhere);
+	Position zero(0);
+	Position one(1);
+	Position minus_one(-1);
+	Position minus_two(-2);
+
+	std::vector<Position> v;
+	v.push_back(begin);
+	v.push_back(end);
+	v.push_back(nowhere);
+	v.push_back(zero);
+	v.push_back(one);
+	v.push_back(minus_one);
+	v.push_back(minus_two);
+	
+	for(int i = 0; i < v.size(); ++i) {
+		for(int j = 0; j < v.size(); ++j) {
+			BOOST_CHECK_EQUAL(i == j, v[i].equals(v[j]));
+			BOOST_CHECK_EQUAL(i == j, v[j].equals(v[i]));
+			if(i >= 2 && j >= 2) { //nowhere, zero, one, minus_one, minus_two
+				BOOST_CHECK_EQUAL(i == j, v[j].equals(v[i], sc));
+				BOOST_CHECK_EQUAL(i == j, v[j].equals(v[i], sc));
+				sc.advance();
+				BOOST_CHECK_EQUAL(i == j, v[j].equals(v[i], sc));
+				BOOST_CHECK_EQUAL(i == j, v[j].equals(v[i], sc));
+				sc.advance();
+				BOOST_CHECK_EQUAL(i == j, v[j].equals(v[i], sc));
+				BOOST_CHECK_EQUAL(i == j, v[j].equals(v[i], sc));
+				sc.goto_start();
+			}
+		}
+	}
+	sc.goto_start();
+	BOOST_CHECK(begin.equals(zero, sc));
+	BOOST_CHECK(zero.equals(begin, sc));
+	BOOST_CHECK(one.equals(end, sc));
+	BOOST_CHECK(end.equals(one, sc));
+	sc.advance();
+	BOOST_CHECK(begin.equals(minus_one, sc));
+	BOOST_CHECK(minus_one.equals(begin, sc));
+	BOOST_CHECK(zero.equals(end, sc));
+	BOOST_CHECK(end.equals(zero, sc));
+	sc.advance();
+	BOOST_CHECK(begin.equals(minus_two, sc));
+	BOOST_CHECK(minus_two.equals(begin, sc));
+	BOOST_CHECK(minus_one.equals(end, sc));
+	BOOST_CHECK(end.equals(minus_one, sc));
+}
+
 BOOST_AUTO_TEST_SUITE_END()