diff --git a/source/simple/support/array_operators.hpp b/source/simple/support/array_operators.hpp
index b2345975ab1aab061dd92a7332af7fa821146839..bf2ed96b2460ad2feb0b1db4c15c4a1ac3f740b8 100644
--- a/source/simple/support/array_operators.hpp
+++ b/source/simple/support/array_operators.hpp
@@ -42,117 +42,123 @@ namespace simple::support
 		all = 			std::numeric_limits<std::underlying_type_t<array_operator>>::max(),
 		binary =		add | mul | sub | div | mod | bit_and | bit_or | bit_xor | lshift | rshift,
 		unary =			bit_not | negate,
+		bitwise = 		bit_and | bit_and_eq | bit_or | bit_or_eq | bit_xor | bit_xor_eq | bit_not,
 		in_place =		all ^ (binary | unary)
 	};
 
 	template<> struct define_enum_flags_operators<array_operator> : public std::true_type {};
 
-	template <typename T1, typename T2 = T1,
-		typename Result = decltype(std::declval<T1&>() += std::declval<const T2&>())>
 	struct add_in_place
 	{
+		template <typename T1, typename T2 = T1,
+			typename Result = decltype(std::declval<T1&>() += std::declval<const T2&>())>
 		constexpr T1& operator()(T1& one, const T2& other) const { return one += other; }
 	};
 
-	template <typename T1, typename T2 = T1,
-		typename Result = decltype(std::declval<T1&>() -= std::declval<const T2&>()) >
 	struct sub_in_place
 	{
+		template <typename T1, typename T2 = T1,
+			typename Result = decltype(std::declval<T1&>() -= std::declval<const T2&>()) >
 		constexpr T1& operator()(T1& one, const T2& other) const { return one -= other; }
 	};
 
-	template <typename T1, typename T2 = T1,
-		typename Result = decltype(std::declval<T1&>() *= std::declval<const T2&>())>
 	struct mul_in_place
 	{
+		template <typename T1, typename T2 = T1,
+			typename Result = decltype(std::declval<T1&>() *= std::declval<const T2&>())>
 		constexpr T1& operator()(T1& one, const T2& other) const { return one *= other; }
 	};
 
-	template <typename T1, typename T2 = T1,
-		typename Result = decltype(std::declval<T1&>() /= std::declval<const T2&>())>
 	struct div_in_place
 	{
+		template <typename T1, typename T2 = T1,
+			typename Result = decltype(std::declval<T1&>() /= std::declval<const T2&>())>
 		constexpr T1& operator()(T1& one, const T2& other) const { return one /= other; }
 	};
 
-	template <typename T1, typename T2 = T1>
 	struct mod_in_place
 	{
-		template <typename TT1 = T1, typename TT2 = T2,
+		template <typename T1, typename T2,
 			std::enable_if_t<
-				std::is_floating_point_v<TT1> && std::is_floating_point_v<TT2>
+				std::is_floating_point_v<T1> && std::is_floating_point_v<T2>
 			> * = nullptr,
-			typename Result = decltype(std::declval<TT1&>() =
-				std::fmod(std::declval<TT1&>(), std::declval<const TT2&>())
+			typename Result = decltype(std::declval<T1&>() =
+				std::fmod(std::declval<T1&>(), std::declval<const T2&>())
 			)
 		>
-		constexpr TT1& operator()(TT1& one, const TT2& other) const
+		constexpr T1& operator()(T1& one, const T2& other) const
 		{
 			return one = std::fmod(one, other);
 		}
 
-		template <typename TT1 = T1, typename TT2 = T2,
+		template <typename T1, typename T2,
 			std::enable_if_t<
-				not(std::is_floating_point_v<TT1> && std::is_floating_point_v<TT2>)
+				not(std::is_floating_point_v<T1> && std::is_floating_point_v<T2>)
 			> * = nullptr,
-			typename Result = decltype(std::declval<TT1&>() %= std::declval<const TT2&>())
+			typename Result = decltype(std::declval<T1&>() %= std::declval<const T2&>())
 		>
-		constexpr TT1& operator()(TT1& one, const TT2& other) const
+		constexpr T1& operator()(T1& one, const T2& other) const
 		{
 			return one %= other;
 		}
 
 	};
 
-	template <typename T1, typename T2 = T1, typename Result =
-		decltype(std::declval<const T1&>() + std::declval<const T2&>())>
+	// TODO: got an opportunity to counter some insane fundamental integral promotion rules here
+	// bool bit_op bool = int // bool is guaranteed to be 0 or 1 so logical bit op results can fit in bool, not to mention bit twiddling an int is implementation defined
+	// (unsigned short) * (unsigned short) = int // overflows for large values, which is undefined behavior for int, should promote to unsigned instead, can't guarantee no overflow, but at least not freakin UB
+	// there is no reason for unary plus to promote, other than if it's used as some sort of explicit promotion operator, but I don't really like that, since proper promotion rules should be based on operators and not just types. in my eyes it unary plus should be just a shorthand for copy construction
+	// // that said it might be better to leave these kind of descisions to the element type instead, but the defaults are just so brokeeeeen T_T the temptatioooon ToT
+
+
 	struct add
 	{
+		template <typename T1, typename T2 = T1, typename Result =
+			decltype(std::declval<const T1&>() + std::declval<const T2&>())>
 		constexpr Result operator()(const T1& one, const T2& other) const { return one + other; }
 	};
 
-	template <typename T1, typename T2 = T1, typename Result =
-		decltype(std::declval<const T1&>() - std::declval<const T2&>())>
 	struct sub
 	{
+		template <typename T1, typename T2 = T1, typename Result =
+			decltype(std::declval<const T1&>() - std::declval<const T2&>())>
 		constexpr Result operator()(const T1& one, const T2& other) const { return one - other; }
 	};
 
-	template <typename T1, typename T2 = T1, typename Result =
-		decltype(std::declval<const T1&>() * std::declval<const T2&>())>
 	struct mul
 	{
+		template <typename T1, typename T2 = T1, typename Result =
+			decltype(std::declval<const T1&>() * std::declval<const T2&>())>
 		constexpr Result operator()(const T1& one, const T2& other) const { return one * other; }
 	};
 
-	template <typename T1, typename T2 = T1, typename Result =
-		decltype(std::declval<const T1&>() / std::declval<const T2&>())>
 	struct div
 	{
+		template <typename T1, typename T2 = T1, typename Result =
+			decltype(std::declval<const T1&>() / std::declval<const T2&>())>
 		constexpr Result operator()(const T1& one, const T2& other) const { return one / other; }
 	};
 
-	template <typename T1, typename T2 = T1>
 	struct mod
 	{
-		template <typename TT1 = T1, typename TT2 = T2,
+		template <typename T1, typename T2,
 			std::enable_if_t<
-				std::is_floating_point_v<TT1> && std::is_floating_point_v<TT2>
+				std::is_floating_point_v<T1> && std::is_floating_point_v<T2>
 			> * = nullptr,
 			typename Result = decltype(
-				std::fmod(std::declval<const TT1&>(), std::declval<const TT2&>())
+				std::fmod(std::declval<const T1&>(), std::declval<const T2&>())
 			)
 		>
 		constexpr Result operator()(const T1& one, const T2& other) const
 		{
 			return std::fmod(one, other);
 		}
-		template <typename TT1 = T1, typename TT2 = T2,
+		template <typename T1, typename T2,
 			std::enable_if_t<
-				not(std::is_floating_point_v<TT1> && std::is_floating_point_v<TT2>)
+				not(std::is_floating_point_v<T1> && std::is_floating_point_v<T2>)
 			> * = nullptr,
 			typename Result = decltype(
-				std::declval<const TT1&>() % std::declval<const TT2&>()
+				std::declval<const T1&>() % std::declval<const T2&>()
 			)
 		>
 		constexpr Result operator()(const T1& one, const T2& other) const
@@ -161,113 +167,159 @@ namespace simple::support
 		}
 	};
 
-	template <typename T1, typename T2 = T1,
-		typename Result = decltype(std::declval<T1&>() &= std::declval<const T2&>())>
 	struct bit_and_in_place
 	{
+		template <typename T1, typename T2 = T1,
+			typename Result = decltype(std::declval<T1&>() &= std::declval<const T2&>())>
 		constexpr T1& operator()(T1& one, const T2& other) const { return one &= other; }
 	};
 
-	template <typename T1, typename T2 = T1,
-		typename Result = decltype(std::declval<T1&>() |= std::declval<const T2&>())>
 	struct bit_or_in_place
 	{
+		template <typename T1, typename T2 = T1,
+			typename Result = decltype(std::declval<T1&>() |= std::declval<const T2&>())>
 		constexpr T1& operator()(T1& one, const T2& other) const { return one |= other; }
 	};
 
-	template <typename T1, typename T2 = T1,
-		typename Result = decltype(std::declval<T1&>() ^= std::declval<const T2&>())>
 	struct bit_xor_in_place
 	{
+		template <typename T1, typename T2 = T1,
+			typename Result = decltype(std::declval<T1&>() ^= std::declval<const T2&>())>
 		constexpr T1& operator()(T1& one, const T2& other) const { return one ^= other; }
 	};
 
-	template <typename T1, typename T2 = T1, typename Result =
-		decltype(std::declval<const T1&>() & std::declval<const T2&>())>
 	struct bit_and
 	{
+		template <typename T1, typename T2 = T1, typename Result =
+			decltype(std::declval<const T1&>() & std::declval<const T2&>())>
 		constexpr Result operator()(const T1& one, const T2& other) const { return one & other; }
 	};
 
-	template <typename T1, typename T2 = T1, typename Result =
-		decltype(std::declval<const T1&>() | std::declval<const T2&>())>
 	struct bit_or
 	{
+		template <typename T1, typename T2 = T1, typename Result =
+			decltype(std::declval<const T1&>() | std::declval<const T2&>())>
 		constexpr Result operator()(const T1& one, const T2& other) const { return one | other; }
 	};
 
-	template <typename T1, typename T2 = T1, typename Result =
-		decltype(std::declval<const T1&>() ^ std::declval<const T2&>())>
 	struct bit_xor
 	{
+		template <typename T1, typename T2 = T1, typename Result =
+			decltype(std::declval<const T1&>() ^ std::declval<const T2&>())>
 		constexpr Result operator()(const T1& one, const T2& other) const { return one ^ other; }
 	};
 
-	template <typename T1, typename T2 = T1, typename Result =
-		decltype(std::declval<const T1&>() << std::declval<const T2&>())>
 	struct lshift
 	{
+		template <typename T1, typename T2 = T1, typename Result =
+			decltype(std::declval<const T1&>() << std::declval<const T2&>())>
 		constexpr Result operator()(const T1& one, const T2& other) const { return one << other; }
 	};
 
-	template <typename T1, typename T2 = T1, typename Result =
-		decltype(std::declval<const T1&>() >> std::declval<const T2&>())>
 	struct rshift
 	{
+		template <typename T1, typename T2 = T1, typename Result =
+			decltype(std::declval<const T1&>() >> std::declval<const T2&>())>
 		constexpr Result operator()(const T1& one, const T2& other) const { return one >> other; }
 	};
 
-	template <typename T1, typename T2 = T1,
-		typename Result = decltype(std::declval<T1&>() <<= std::declval<const T2&>())>
 	struct lshift_in_place
 	{
+		template <typename T1, typename T2 = T1,
+			typename Result = decltype(std::declval<T1&>() <<= std::declval<const T2&>())>
 		constexpr T1& operator()(T1& one, const T2& other) const { return one <<= other; }
 	};
 
-	template <typename T1, typename T2 = T1,
-		typename Result = decltype(std::declval<T1&>() >>= std::declval<const T2&>())>
 	struct rshift_in_place
 	{
+		template <typename T1, typename T2 = T1,
+			typename Result = decltype(std::declval<T1&>() >>= std::declval<const T2&>())>
 		constexpr T1& operator()(T1& one, const T2& other) const { return one >>= other; }
 	};
 
-	template <typename Type, typename Result = decltype(~std::declval<const Type&>())>
 	struct bit_not
 	{
+		template <typename Type, typename Result = decltype(~std::declval<const Type&>())>
 		constexpr Result operator()(const Type& one) const { return ~one; }
 	};
 
-	// public
+	struct negate
+	{
+		template <typename Type, typename Result = decltype(-std::declval<const Type&>())>
+		constexpr Result operator()(const Type& one) const { return -one; }
+	};
+
+	// public trait to specialize
 	template <typename Type>
 	struct define_array_operators
 	{
+		// specify the size of the array for the purposes of these operators
 		constexpr static size_t size = 0;
+
+		// 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);
+
+		// operators to enable, only considering operands that define this trait
 		constexpr static array_operator enabled_operators = array_operator::none;
+		// binary and in_place operators to enable, considering element types on the right side
 		constexpr static array_operator enabled_right_element_operators = array_operator::none;
+		// binary and in_place operators to enable, considering element types on the left side
 		constexpr static array_operator enabled_left_element_operators = array_operator::none;
+
+		// this template is used to change the element type of the array
+		// in context of deducing the result of binary operations,
+		// if your array-like type is templated on the element type you can wire it through here
+		// to support type promotion, expression templates or other special techniques (like boost safe_numerics)
+		// 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>
+		using result = Type;
+
+		// if this type is the same between two types they will be considered as operands for binary and in-place operators,
+		// as long as corresponding element types support the operator,
+		// 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
+		using compatibility_tag = Type;
 	};
 
+	// public trait to use
+	// some common defaults for defining array operators on a type
 	template <typename Type, size_t Size>
 	struct trivial_array_accessor
 	{
-		constexpr static size_t size = Size;
-		constexpr static Type& get_array(Type& object) noexcept { return object; }
-		constexpr static const Type& get_array(const Type& object) noexcept { return object; }
+		constexpr static size_t size = Size; // explicitly specified size
+
+		// the type provides array-like interface itself, no digging or wrapping necessary
+		template <typename T>
+		constexpr static T& get_array(T& object) noexcept { return object; }
+		template <typename T>
+		constexpr static const T& get_array(const T& object) noexcept { return object; }
+
+		template <typename Result, array_operator, typename Other = Type>
+		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
+		// see https://www.boost.org/doc/libs/1_75_0/libs/safe_numerics/doc/html/promotion_policy.html
+
+		using compatibility_tag = Type; // operands of binary and in-place operators must be the same exact type
 	};
 
-	// public
-	template <typename T>
-	struct array_operator_implicit_conversion { using type = support::remove_cvref_t<T>; };
-	template <typename T>
+	// public trait to specialize
+	// allows you to specify an implicit conversion to be considered by binary and in-place operators,
+	// since templates do not considered conversions otherwise
+	template <typename From>
+	struct array_operator_implicit_conversion { using type = support::remove_cvref_t<From>; };
+	template <typename From>
 	using array_operator_implicit_conversion_t =
-		typename array_operator_implicit_conversion<support::remove_cvref_t<T>>::type;
+		typename array_operator_implicit_conversion<support::remove_cvref_t<From>>::type;
 
 namespace AOps_Details
 {
 
-	template <typename Operator, size_t Size, typename Type>
-	constexpr Type& array_unary_operator(Type& result, const Type& one)
+	template <typename Operator, size_t Size, typename Type, typename Result>
+	constexpr Result& array_unary_operator(Result& result, const Type& one)
 	{
 		auto op = Operator{};
 		for(size_t i = 0; i < Size; ++i)
@@ -275,8 +327,8 @@ namespace AOps_Details
 		return result;
 	}
 
-	template <typename Operator, size_t Size, typename Type>
-	constexpr Type& array_in_place_operator(Type& one, const Type& other)
+	template <typename Operator, size_t Size, typename Type, typename Other>
+	constexpr Type& array_in_place_operator(Type& one, const Other& other)
 	{
 		auto op = Operator{};
 		for(size_t i = 0; i < Size; ++i)
@@ -302,8 +354,8 @@ namespace AOps_Details
 		return element;
 	}
 
-	template <typename Operator, size_t Size, typename Type>
-	constexpr Type& array_binary_operator(Type& result, const Type& one, const Type& other)
+	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)
 	{
 		auto op = Operator{};
 		for(size_t i = 0; i < Size; ++i)
@@ -343,50 +395,60 @@ namespace AOps_Details
 template <typename Array, \
 	typename OperatorDef = simple::support::define_array_operators<Array>, \
 	std::enable_if_t<OperatorDef::enabled_operators && simple::support::array_operator::op_type>* = nullptr> \
-[[nodiscard]] constexpr Array operator op_symbol (const Array& one) \
+[[nodiscard]] constexpr auto operator op_symbol (const Array& one) \
 { \
 	using namespace simple::support; \
 	using namespace simple::support::AOps_Details; \
-	Array result{}; \
+	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>; \
+	result_t result{}; \
 	array_unary_operator \
-		<op_fun<array_element_t<OperatorDef, Array>>, OperatorDef::size> \
+		<op_fun, OperatorDef::size> \
 		(OperatorDef::get_array(result), OperatorDef::get_array(one)); \
 	return result; \
 }
 
 SIMPLE_SUPPORT_DEFINE_UNARY_OPERATOR(~, bit_not, simple::support::bit_not)
-SIMPLE_SUPPORT_DEFINE_UNARY_OPERATOR(-, negate, std::negate)
+SIMPLE_SUPPORT_DEFINE_UNARY_OPERATOR(-, negate, simple::support::negate)
 
 #undef SIMPLE_SUPPORT_DEFINE_UNARY_OPERATOR
 
 #define SIMPLE_SUPPORT_DEFINE_BINARY_OPERATOR(op_symbol, op_type, op_fun) \
-template <typename Array, void* = nullptr, \
+template <typename Array, typename Other,  void* = nullptr, \
 	typename OperatorDef = simple::support::define_array_operators<Array>, \
-	std::enable_if_t<OperatorDef::enabled_operators && simple::support::array_operator::op_type>* = nullptr> \
-[[nodiscard]] constexpr Array operator op_symbol (const Array& one, const Array& other) \
+	typename OtherOperatorDef = simple::support::define_array_operators<Other>, \
+	typename Element = simple::support::AOps_Details::array_element_t<OperatorDef, Array>, \
+	typename OtherElement = simple::support::AOps_Details::array_element_t<OtherOperatorDef, Other>, \
+	std::enable_if_t<OperatorDef::enabled_operators && simple::support::array_operator::op_type>* = nullptr, \
+	std::enable_if_t<OtherOperatorDef::enabled_operators && simple::support::array_operator::op_type>* = nullptr, \
+	std::enable_if_t<std::is_same_v<typename OtherOperatorDef::compatibility_tag, typename OperatorDef::compatibility_tag>>* = nullptr, \
+	std::enable_if_t<std::is_invocable_v<op_fun,Element,OtherElement>>* = nullptr> \
+[[nodiscard]] constexpr auto operator op_symbol (const Array& one, const Other& other) \
 { \
 	using namespace simple::support; \
 	using namespace simple::support::AOps_Details; \
-	Array result{}; \
+	using result_t = typename OperatorDef::template result<std::invoke_result_t<op_fun,Element,OtherElement>, simple::support::array_operator::op_type, OtherElement>; \
+	result_t result{}; \
+	using result_op_def = simple::support::define_array_operators<result_t>; \
+	static_assert(result_op_def::size == OperatorDef::size); \
 	array_binary_operator \
-		<op_fun<array_element_t<OperatorDef, Array>>, OperatorDef::size> \
-		(OperatorDef::get_array(result), OperatorDef::get_array(one), OperatorDef::get_array(other)); \
+		<op_fun, OperatorDef::size> \
+		(result_op_def::get_array(result), OperatorDef::get_array(one), OtherOperatorDef::get_array(other)); \
 	return result; \
 } \
 \
 template <typename T1, typename T2, \
 	typename C1 = simple::support::array_operator_implicit_conversion_t<T1>, \
 	typename C2 = simple::support::array_operator_implicit_conversion_t<T2>, \
-	typename OperatorDef = simple::support::define_array_operators<C1>, \
 	std::enable_if_t< \
-		(OperatorDef::enabled_operators && simple::support::array_operator::op_type) \
-		&& std::is_same_v<C1,C2> \
-		&& (!std::is_same_v<T1,C1> || !std::is_same_v<T2,C2>) \
+		(!std::is_same_v<T1,C1> || !std::is_same_v<T2,C2>) \
 	>* = nullptr \
 > \
 [[nodiscard]] constexpr auto operator op_symbol (T1&& one, T2&& other) \
+	-> decltype(operator op_symbol<C1,C2,nullptr>(std::forward<T1>(one), std::forward<T2>(other))) \
 { \
-	return operator op_symbol<C1,nullptr>(std::forward<T1>(one), std::forward<T2>(other)); \
+	return operator op_symbol<C1,C2,nullptr>(std::forward<T1>(one), std::forward<T2>(other)); \
 } \
 \
 template <typename Array, typename Other, \
@@ -394,7 +456,7 @@ template <typename Array, typename 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>, Element, Other>\
+		&& std::is_invocable_r_v<Element, op_fun, Element, Other>\
 	>* = nullptr \
 > \
 [[nodiscard]] constexpr Array operator op_symbol \
@@ -407,7 +469,7 @@ template <typename Array, typename Other, \
 	using namespace simple::support::AOps_Details; \
 	Array result{}; \
 	array_right_element_binary_operator \
-		<op_fun<Element,Other>, OperatorDef::size> \
+		<op_fun, OperatorDef::size> \
 		(OperatorDef::get_array(result), OperatorDef::get_array(one), other); \
 	return result; \
 } \
@@ -417,7 +479,7 @@ template <typename Array, typename 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>, Other, Element>\
+		&& std::is_invocable_r_v<Element, op_fun, Other, Element>\
 	>* = nullptr \
 > \
 [[nodiscard]] constexpr Array operator op_symbol \
@@ -430,7 +492,7 @@ template <typename Array, typename Other, \
 	using namespace simple::support::AOps_Details; \
 	Array result{}; \
 	array_left_element_binary_operator \
-		<op_fun<Other,Element>, OperatorDef::size> \
+		<op_fun, OperatorDef::size> \
 		(OperatorDef::get_array(result), OperatorDef::get_array(other), one); \
 	return result; \
 }
@@ -449,28 +511,47 @@ SIMPLE_SUPPORT_DEFINE_BINARY_OPERATOR(>>, rshift, simple::support::rshift)
 #undef SIMPLE_SUPPORT_DEFINE_BINARY_OPERATOR
 
 #define SIMPLE_SUPPORT_DEFINE_IN_PLACE_OPERATOR(op_symbol, op_type, op_fun) \
-template <typename Array, \
+template <typename Array, typename Other, void* = nullptr, \
 	typename OperatorDef = simple::support::define_array_operators<Array>, \
-	std::enable_if_t<OperatorDef::enabled_operators && simple::support::array_operator::op_type>* = nullptr> \
+	typename OtherOperatorDef = simple::support::define_array_operators<Other>, \
+	typename Element = simple::support::AOps_Details::array_element_t<OperatorDef, Array>, \
+	typename OtherElement = simple::support::AOps_Details::array_element_t<OtherOperatorDef, Other>, \
+	std::enable_if_t<OperatorDef::enabled_operators && simple::support::array_operator::op_type>* = nullptr, \
+	std::enable_if_t<OtherOperatorDef::enabled_operators && simple::support::array_operator::op_type>* = nullptr, \
+	std::enable_if_t<std::is_same_v<typename OtherOperatorDef::compatibility_tag, typename OperatorDef::compatibility_tag>>* = nullptr, \
+	std::enable_if_t<std::is_invocable_v<op_fun,Element&,const OtherElement&>>* = nullptr> \
 constexpr Array& operator op_symbol \
 ( \
 	Array& one, \
-	const simple::support::non_deduced<Array>& other \
+	const Other& other \
 ) \
 { \
 	using namespace simple::support; \
 	using namespace simple::support::AOps_Details; \
 	array_in_place_operator \
-		<op_fun<array_element_t<OperatorDef, Array>>, OperatorDef::size> \
-		(OperatorDef::get_array(one), OperatorDef::get_array(other)); \
+		<op_fun, OperatorDef::size> \
+		(OperatorDef::get_array(one), OtherOperatorDef::get_array(other)); \
 	return one; \
 } \
+\
+template <typename Array, typename Other, \
+	typename OtherConv = simple::support::array_operator_implicit_conversion_t<Other>, \
+	std::enable_if_t< \
+		(!std::is_same_v<OtherConv,Other>) \
+	>* = nullptr \
+> \
+constexpr auto operator op_symbol (Array& one, const Other& other) \
+	-> decltype(operator op_symbol<Array,OtherConv,nullptr>(one, other)) \
+{ \
+	return operator op_symbol<Array,OtherConv,nullptr>(one, other); \
+} \
+\
 template <typename Array, typename Other, \
 	typename OperatorDef = simple::support::define_array_operators<Array>, \
 	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>, Element&, Other> \
+		&& std::is_invocable_r_v<Element&, op_fun, Element&, Other> \
 	>* = nullptr \
 > \
 constexpr Array& operator op_symbol \
@@ -482,7 +563,7 @@ constexpr Array& operator op_symbol \
 	using namespace simple::support; \
 	using namespace simple::support::AOps_Details; \
 	array_right_element_in_place_operator \
-		<op_fun<Element,Other>, OperatorDef::size> \
+		<op_fun, OperatorDef::size> \
 		(OperatorDef::get_array(one), other); \
 	return one; \
 } \
@@ -491,7 +572,7 @@ template <typename Array, typename 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>, Other&, Element> \
+		&& std::is_invocable_r_v<Element&, op_fun, Other&, Element> \
 	>* = nullptr \
 > \
 constexpr Other& operator op_symbol \
@@ -503,7 +584,7 @@ constexpr Other& operator op_symbol \
 	using namespace simple::support; \
 	using namespace simple::support::AOps_Details; \
 	array_left_element_in_place_operator \
-		<op_fun<Other,Element>, OperatorDef::size> \
+		<op_fun, OperatorDef::size> \
 		(one, OperatorDef::get_array(other)); \
 	return one; \
 }
diff --git a/source/simple/support/rational.hpp b/source/simple/support/rational.hpp
index 805871053587ddd0bd38e25e86f5b5ea20373c60..8e3f405bf1b4df35c1b0510cd53bcfb0c90df850 100644
--- a/source/simple/support/rational.hpp
+++ b/source/simple/support/rational.hpp
@@ -3,6 +3,7 @@
 
 #include "array.hpp"
 #include "array_operators.hpp"
+#include "type_traits.hpp"
 
 namespace simple::support
 {
@@ -23,21 +24,21 @@ namespace simple::support
 			return *this;
 		}
 
-		constexpr operator Int() const
+		constexpr explicit operator Int() const
 		{
 			return (*this)[numerator] / (*this)[denominator];
 		}
 	};
 
 	template <typename Int>
-	constexpr rational<Int> operator*(rational<Int> ratio, const Int& value)
+	constexpr rational<Int> operator*(rational<Int> ratio, const non_deduced<Int>& value)
 	{
 		ratio *= value;
 		return ratio;
 	}
 
 	template <typename Int>
-	constexpr rational<Int> operator*(const Int& value, rational<Int> ratio)
+	constexpr rational<Int> operator*(const non_deduced<Int>& value, rational<Int> ratio)
 	{
 		ratio *= value;
 		return ratio;
diff --git a/unit_tests/rational.cpp b/unit_tests/rational.cpp
index 31b59db8d298c314eb32d5d03889c89826872efb..8c7333ac713e705410d507fa941f3352a7f6e0a6 100644
--- a/unit_tests/rational.cpp
+++ b/unit_tests/rational.cpp
@@ -4,27 +4,27 @@ using simple::support::rational;
 
 constexpr bool Ratio()
 {
-	static_assert(10 * rational{1,2} == 5);
-	static_assert(9 * rational{1,2} == 4);
-	static_assert(9 * rational{1.0,2.0} == 4.5);
-	static_assert(rational{1,3} * 9 == 3);
-	static_assert(rational{1,3} * rational{5,2} * 12 == 10);
-	static_assert(13 * rational{5,2} * rational{2,5} == 13);
+	static_assert(int(10 * rational{1,2}) == 5);
+	static_assert(int(9 * rational{1,2}) == 4);
+	static_assert(double(9 * rational{1.0,2.0}) == 4.5);
+	static_assert(int(rational{1,3} * 9) == 3);
+	static_assert(int(rational{1,3} * rational{5,2} * 12) == 10);
+	static_assert(int(13 * rational{5,2} * rational{2,5}) == 13);
 
 	bool assertion = true;
 
 	auto ratio = rational{1,2};
-	assertion &= ratio == 0;
+	assertion &= int(ratio) == 0;
 	ratio *= 2;
-	assertion &= ratio == 1;
+	assertion &= int(ratio) == 1;
 	ratio *= 3;
-	assertion &= ratio == 3;
+	assertion &= int(ratio) == 3;
 	ratio *= rational{1,2};
-	assertion &= ratio == 1;
+	assertion &= int(ratio) == 1;
 	ratio *= 5;
-	assertion &= ratio == 7;
+	assertion &= int(ratio) == 7;
 	ratio *= 2;
-	assertion &= ratio == 15;
+	assertion &= int(ratio) == 15;
 
 	return assertion;
 }