diff --git a/source/simple/support/algorithm/utils.hpp b/source/simple/support/algorithm/utils.hpp
index 5536e88faf9a807c20af9a9610d4b8e5038aff8f..2da935599bc402c0b613df9e3f6c847ac5c87bb9 100644
--- a/source/simple/support/algorithm/utils.hpp
+++ b/source/simple/support/algorithm/utils.hpp
@@ -45,7 +45,9 @@ namespace simple::support
 		return make_range(std::forward<Container>(container)).sub_range(index_range);
 	}
 
+	// TODO: maybe useful if generalized to any range like type, and makes use of std::ditance
 	template<typename It>
+	[[deprecated("no reason to use this anymore, can just subtract the origin from the range now")]]
 	[[nodiscard]] constexpr
 	auto distance(const range<It>& rng, const It& origin)
 	{
diff --git a/source/simple/support/array_operators.hpp b/source/simple/support/array_operators.hpp
index 49db9b99e6de4837aa0706345d801537d5f2ac8f..5fb7617566fab296b33240a1c296539ae8941341 100644
--- a/source/simple/support/array_operators.hpp
+++ b/source/simple/support/array_operators.hpp
@@ -254,10 +254,11 @@ namespace simple::support
 	struct define_array_operators
 	{
 		// specify the size of the array for the purposes of these operators
-		constexpr static size_t size = 0;
+		constexpr static size_t size = 1;
 
 		// a way to get to an actual array-like type in case Type does not expose the interface
-		constexpr static auto& get_array(Type& object);
+		constexpr static Type* get_array(Type& object) noexcept
+		{return &object;}
 
 		// operators to enable, only considering operands that define this trait
 		constexpr static array_operator enabled_operators = array_operator::none;
@@ -273,7 +274,8 @@ namespace simple::support
 		// Result - the deduced result element type
 		// array_operator - the operator in question
 		// Other - the element type of the other operand (for unary ops it's same as Type)
-		template <typename Result, array_operator, typename Other = Type>
+		// Element - indicates whether this is an right/left element operation
+		template <typename Result, array_operator, typename Other = Type, bool Element = false>
 		using result = Type;
 
 		// if this type is the same between two types they will be considered as operands for binary and in-place operators,
@@ -281,7 +283,7 @@ namespace simple::support
 		// this is the another thing you need in order to support type promotion, expression templates etc.
 		// you can set this to the shape of the array (which would be size if there is no nesting),
 		// along with a tag that identifies the template, if you want that extra safety
-		// TODO: this is about operands so include operand in the name, perhaps simply operand_tag
+		// TODO: implement a compatibility_check boolean variable template instead of (or in addition to) this tag, it would be more generic, and allow, for example, making all arithmetic types compatible... in general I would say if arithmetic can be done on two types than they are compatible, so maybe it should also be parameterized on the operator
 		using compatibility_tag = Type;
 	};
 
@@ -298,7 +300,7 @@ namespace simple::support
 		template <typename T>
 		constexpr static const T& get_array(const T& object) noexcept { return object; }
 
-		template <typename Result, array_operator, typename Other = Type>
+		template <typename Result, array_operator, typename Other = Type, bool Element = false>
 		using result = Type; // the result of binary operators is the same exact type, in all cases
 		// note that, while it can help somewhat, this does not (and can not) technically prevent type promotion and associated problems,
 		// to get around that properly you would need a more sophisticated solution
@@ -320,66 +322,59 @@ namespace AOps_Details
 {
 
 	template <typename Operator, size_t Size, typename Type, typename Result>
-	constexpr Result& array_unary_operator(Result& result, const Type& one)
+	constexpr void array_unary_operator(Result&& result, const Type& one)
 	{
 		auto op = Operator{};
 		for(size_t i = 0; i < Size; ++i)
 			result[i] = op(one[i]);
-		return result;
 	}
 
 	template <typename Operator, size_t Size, typename Type, typename Other>
-	constexpr Type& array_in_place_operator(Type& one, const Other& other)
+	constexpr void array_in_place_operator(Type&& one, const Other& other)
 	{
 		auto op = Operator{};
 		for(size_t i = 0; i < Size; ++i)
 			op(one[i], other[i]);
-		return one;
 	}
 
 	template <typename Operator, size_t Size, typename Type, typename Element>
-	constexpr Type& array_right_element_in_place_operator(Type& one, const Element& element)
+	constexpr void array_right_element_in_place_operator(Type&& one, const Element& element)
 	{
 		auto op = Operator{};
 		for(size_t i = 0; i < Size; ++i)
 			op(one[i], element);
-		return one;
 	}
 
 	template <typename Operator, size_t Size, typename Type, typename Element>
-	constexpr Element& array_left_element_in_place_operator(Element& element, const Type& array)
+	constexpr void array_left_element_in_place_operator(Element& element, const Type& array)
 	{
 		auto op = Operator{};
 		for(size_t i = 0; i < Size; ++i)
 			op(element, array[i]);
-		return element;
 	}
 
 	template <typename Operator, size_t Size, typename One, typename Other, typename Result>
-	constexpr Result& array_binary_operator(Result& result, const One& one, const Other& other)
+	constexpr void array_binary_operator(Result&& result, const One& one, const Other& other)
 	{
 		auto op = Operator{};
 		for(size_t i = 0; i < Size; ++i)
 			result[i] = op(one[i], other[i]);
-		return result;
 	}
 
-	template <typename Operator, size_t Size, typename Type, typename Element>
-	constexpr Type& array_right_element_binary_operator(Type& result, const Type& one, const Element& element)
+	template <typename Operator, size_t Size, typename Type, typename Element, typename Result>
+	constexpr void array_right_element_binary_operator(Result&& result, const Type& one, const Element& element)
 	{
 		auto op = Operator{};
 		for(size_t i = 0; i < Size; ++i)
 			result[i] = op(one[i], element);
-		return result;
 	}
 
-	template <typename Operator, size_t Size, typename Type, typename Element>
-	constexpr Type& array_left_element_binary_operator(Type& result, const Type& one, const Element& element)
+	template <typename Operator, size_t Size, typename Type, typename Element, typename Result>
+	constexpr void array_left_element_binary_operator(Result&& result, const Type& one, const Element& element)
 	{
 		auto op = Operator{};
 		for(size_t i = 0; i < Size; ++i)
 			result[i] = op(element, one[i]);
-		return result;
 	}
 
 	template <typename OperatorDef, typename Type>
@@ -402,7 +397,7 @@ template <typename Array, \
 	using namespace simple::support::AOps_Details; \
 	using element_t = simple::support::AOps_Details::array_element_t<OperatorDef, Array>; \
 	using result_element_t = std::invoke_result_t<op_fun,element_t>; \
-	using result_t = typename OperatorDef::template result<result_element_t, simple::support::array_operator::op_type, element_t>; \
+	using result_t = typename OperatorDef::template result<result_element_t, simple::support::array_operator::op_type, element_t, false>; \
 	result_t result{}; \
 	array_unary_operator \
 		<op_fun, OperatorDef::size> \
@@ -429,7 +424,7 @@ template <typename Array, typename Other,  void* = nullptr, \
 { \
 	using namespace simple::support; \
 	using namespace simple::support::AOps_Details; \
-	using result_t = typename OperatorDef::template result<std::invoke_result_t<op_fun,Element,OtherElement>, simple::support::array_operator::op_type, OtherElement>; \
+	using result_t = typename OperatorDef::template result<std::invoke_result_t<op_fun,Element,OtherElement>, simple::support::array_operator::op_type, OtherElement, false>; \
 	result_t result{}; \
 	using result_op_def = simple::support::define_array_operators<result_t>; \
 	static_assert(result_op_def::size == OperatorDef::size); \
@@ -454,13 +449,31 @@ template <typename T1, typename T2, \
 \
 template <typename Array, typename Other, \
 	typename OperatorDef = simple::support::define_array_operators<Array>, \
+	typename OtherOperatorDef = simple::support::define_array_operators<Other>, \
 	typename Element = simple::support::AOps_Details::array_element_t<OperatorDef, Array>, \
-	std::enable_if_t<(OperatorDef::enabled_right_element_operators && simple::support::array_operator::op_type) \
-		&& !std::is_same_v<Array, Other> \
-		&& std::is_invocable_r_v<Element, op_fun, Element, Other>\
+	typename ElementOpDef = simple::support::define_array_operators<Element>, \
+	typename OtherElement = simple::support::AOps_Details::array_element_t<OtherOperatorDef, Other>, \
+	typename OtherElOpDef = simple::support::define_array_operators<OtherElement>, \
+	bool ops_defined = OperatorDef::enabled_right_element_operators && simple::support::array_operator::op_type, \
+	typename Result = typename OperatorDef::template result<std::conditional_t<ops_defined, std::invoke_result_t<op_fun,Element,Other>, Element>, simple::support::array_operator::op_type, Other, true>, \
+	typename ResultOpDef = simple::support::define_array_operators<Result>, \
+	std::enable_if_t<(ops_defined) \
+		&& !std::is_same_v< \
+			typename OperatorDef::compatibility_tag, \
+			typename OtherOperatorDef::compatibility_tag> \
+		&& !std::is_same_v< \
+			typename OperatorDef::compatibility_tag, \
+			typename OtherElOpDef::compatibility_tag> \
+		&& (std::is_same_v< \
+			typename ElementOpDef::compatibility_tag, \
+			typename OtherOperatorDef::compatibility_tag> \
+			|| std::is_same_v< \
+			typename ResultOpDef::compatibility_tag, \
+			typename OperatorDef::compatibility_tag>) \
+		&& std::is_invocable_v<op_fun, Element, Other>\
 	>* = nullptr \
 > \
-[[nodiscard]] constexpr Array operator op_symbol \
+[[nodiscard]] constexpr auto operator op_symbol \
 ( \
 	const Array & one, \
 	const Other & other \
@@ -468,22 +481,40 @@ template <typename Array, typename Other, \
 { \
 	using namespace simple::support; \
 	using namespace simple::support::AOps_Details; \
-	Array result{}; \
+	Result result{}; \
 	array_right_element_binary_operator \
 		<op_fun, OperatorDef::size> \
-		(OperatorDef::get_array(result), OperatorDef::get_array(one), other); \
+		(ResultOpDef::get_array(result), OperatorDef::get_array(one), other); \
 	return result; \
 } \
 \
 template <typename Array, typename Other, \
 	typename OperatorDef = simple::support::define_array_operators<Array>, \
+	typename OtherOperatorDef = simple::support::define_array_operators<Other>, \
 	typename Element = simple::support::AOps_Details::array_element_t<OperatorDef, Array>, \
-	std::enable_if_t<(OperatorDef::enabled_left_element_operators && simple::support::array_operator::op_type) \
-		&& !std::is_same_v<Array, Other> \
-		&& std::is_invocable_r_v<Element, op_fun, Other, Element>\
+	typename ElementOpDef = simple::support::define_array_operators<Element>, \
+	typename OtherElement = simple::support::AOps_Details::array_element_t<OtherOperatorDef, Other>, \
+	typename OtherElOpDef = simple::support::define_array_operators<OtherElement>, \
+	bool ops_defined = OperatorDef::enabled_left_element_operators && simple::support::array_operator::op_type, \
+	typename Result = typename OperatorDef::template result<std::conditional_t<ops_defined, std::invoke_result_t<op_fun,Other,Element>, Element>, simple::support::array_operator::op_type, Other, true>, \
+	typename ResultOpDef = simple::support::define_array_operators<Result>, \
+	std::enable_if_t<(ops_defined) \
+		&& !std::is_same_v< \
+			typename OperatorDef::compatibility_tag, \
+			typename OtherOperatorDef::compatibility_tag> \
+		&& !std::is_same_v< \
+			typename OperatorDef::compatibility_tag, \
+			typename OtherElOpDef::compatibility_tag> \
+		&& (std::is_same_v< \
+			typename ElementOpDef::compatibility_tag, \
+			typename OtherOperatorDef::compatibility_tag> \
+			|| std::is_same_v< \
+			typename ResultOpDef::compatibility_tag, \
+			typename OperatorDef::compatibility_tag>) \
+		&& std::is_invocable_v<op_fun, Other, Element>\
 	>* = nullptr \
 > \
-[[nodiscard]] constexpr Array operator op_symbol \
+[[nodiscard]] constexpr auto operator op_symbol \
 ( \
 	const Other & one, \
 	const Array & other \
@@ -491,10 +522,10 @@ template <typename Array, typename Other, \
 { \
 	using namespace simple::support; \
 	using namespace simple::support::AOps_Details; \
-	Array result{}; \
+	Result result{}; \
 	array_left_element_binary_operator \
 		<op_fun, OperatorDef::size> \
-		(OperatorDef::get_array(result), OperatorDef::get_array(other), one); \
+		(ResultOpDef::get_array(result), OperatorDef::get_array(other), one); \
 	return result; \
 }
 
diff --git a/source/simple/support/range.hpp b/source/simple/support/range.hpp
index 074bf0d14fa6de311c6315337f43f81d09068310..d0f839ebbac040f0006c2bd5658a85cf7403ee4c 100644
--- a/source/simple/support/range.hpp
+++ b/source/simple/support/range.hpp
@@ -40,6 +40,7 @@ namespace simple::support
 			return { std::numeric_limits<Type>::lowest(), std::numeric_limits<Type>::max() };
 		}
 
+
 		constexpr Type& lower() noexcept { return bounds[0]; }
 		constexpr Type& upper() noexcept { return bounds[1]; }
 		constexpr const Type& lower() const noexcept { return bounds[0]; }
@@ -152,6 +153,31 @@ namespace simple::support
 			return other;
 		}
 
+		template <typename Other, std::enable_if_t<
+			std::is_convertible_v<Type, Other>
+		>* = nullptr>
+		operator range<Other> ()
+		{
+			return
+			{
+				static_cast<Other>(lower()),
+				static_cast<Other>(upper())
+			};
+		}
+
+		template <typename Other, std::enable_if_t<
+			!std::is_convertible_v<Type, Other> &&
+			std::is_constructible_v<Type, Other>
+		>* = nullptr>
+		explicit operator range<Other> ()
+		{
+			return
+			{
+				static_cast<Other>(lower()),
+				static_cast<Other>(upper())
+			};
+		}
+
 	};
 
 	template <typename T> range(T lower, T upper) -> range<T>;
@@ -239,6 +265,8 @@ namespace simple::support
 		return range<T>{std::forward<T>(lower), std::forward<T>(upper)};
 	}
 
+	class range_operators_compatibility_tag {};
+
 } // namespace simple::support
 
 namespace simple
@@ -263,6 +291,11 @@ namespace simple
 		{ return r.bounds; }
 		constexpr static const array<T,size>& get_array(const support::range<T>& r) noexcept
 		{ return r.bounds; }
+
+		template <typename R, array_operator, typename, bool>
+		using result = support::range<R>;
+
+		using compatibility_tag = support::range_operators_compatibility_tag;
 	};
 } // namespace simple
 
diff --git a/unit_tests/range.cpp b/unit_tests/range.cpp
index e7852aa15aca6c1806a02e9a1d3ed4adee5147b5..796dc6fd6cd238f6615eedc4f8720443e5734897 100644
--- a/unit_tests/range.cpp
+++ b/unit_tests/range.cpp
@@ -211,13 +211,13 @@ void Limit()
 void Arithmetic()
 {
 	{range<float> r{-1,1};
-		assert(( r + 0.25 == range<float>{-0.75,1.25} ));
+		assert(( r + 0.25 == range<double>{-0.75,1.25} ));
 		r += 0.25;
 		assert(( r == range<float>{-0.75,1.25} ));
 	}
 
 	{range<float> r{-1,1};
-		assert(( r - 0.25 == range<float>{-1.25,0.75} ));
+		assert(( r - 0.25 == range<double>{-1.25,0.75} ));
 		r -= 0.25;
 		assert(( r == range<float>{-1.25,0.75} ));
 	}