diff -r 435878fa6d33 libinterp/octave-value/ov-complex.h
--- a/libinterp/octave-value/ov-complex.h	Tue Feb 28 19:34:27 2023 -0500
+++ b/libinterp/octave-value/ov-complex.h	Wed Mar 01 09:13:22 2023 -0500
@@ -128,7 +128,7 @@ public:
   OCTINTERP_API octave_value
   resize (const dim_vector& dv, bool fill = false) const;
 
-  OCTINTERP_API Complex complex_value (bool = false) const;
+  OCTINTERP_API Complex complex_value (bool = false) const final;
 
   OCTINTERP_API FloatComplex float_complex_value (bool = false) const;
 
diff -r 435878fa6d33 libinterp/octave-value/ov-scalar.h
--- a/libinterp/octave-value/ov-scalar.h	Tue Feb 28 19:34:27 2023 -0500
+++ b/libinterp/octave-value/ov-scalar.h	Wed Mar 01 09:13:22 2023 -0500
@@ -144,7 +144,7 @@ public:
 
 #undef DEFINE_INT_SCALAR_VALUE
 
-  double double_value (bool = false) const { return scalar; }
+  double double_value (bool = false) const final { return scalar; }
 
   float float_value (bool = false) const
   { return static_cast<float> (scalar); }
@@ -203,7 +203,7 @@ public:
     return retval;
   }
 
-  bool bool_value (bool warn = false) const
+  bool bool_value (bool warn = false) const final
   {
     if (octave::math::isnan (scalar))
       octave::err_nan_to_logical_conversion ();
diff -r 435878fa6d33 libinterp/octave-value/ov.h
--- a/libinterp/octave-value/ov.h	Tue Feb 28 19:34:27 2023 -0500
+++ b/libinterp/octave-value/ov.h	Wed Mar 01 09:13:22 2023 -0500
@@ -1519,6 +1519,10 @@ protected:
   octave_base_value *m_rep;
 
 private:
+  // For use by inline octave_value "factory" octave_value_inline
+  octave_value (int /* dummy */, octave_base_value *rep) : m_rep (rep) {}
+
+  friend class octave_value_factory;
 
   // Special class to make a octave_base_value that will never have a zero count
   // so that we can create a static octave_base_value and not call delete on it
diff -r 435878fa6d33 libinterp/operators/op-b-b.cc
--- a/libinterp/operators/op-b-b.cc	Tue Feb 28 19:34:27 2023 -0500
+++ b/libinterp/operators/op-b-b.cc	Wed Mar 01 09:13:22 2023 -0500
@@ -81,10 +81,10 @@ DEFUNOP_OP (hermitian, bool, /* no-op */
 
 // bool by bool ops.
 
-DEFBINOP_OP (eq, bool, bool, ==)
-DEFBINOP_OP (ne, bool, bool, !=)
-DEFBINOP_OP (el_and, bool, bool, &&)
-DEFBINOP_OP (el_or, bool, bool, ||)
+DEFBINOP_SCALAR_OP (eq, bool, bool, ==)
+DEFBINOP_SCALAR_OP (ne, bool, bool, !=)
+DEFBINOP_SCALAR_OP (el_and, bool, bool, &&)
+DEFBINOP_SCALAR_OP (el_or, bool, bool, ||)
 
 DEFNDCATOP_FN (b_b, bool, bool, bool_array, bool_array, concat)
 DEFNDCATOP_FN (b_s, bool, scalar, array, array, concat)
diff -r 435878fa6d33 libinterp/operators/op-cs-cs.cc
--- a/libinterp/operators/op-cs-cs.cc	Tue Feb 28 19:34:27 2023 -0500
+++ b/libinterp/operators/op-cs-cs.cc	Wed Mar 01 09:13:22 2023 -0500
@@ -51,18 +51,18 @@ DEFUNOP (not, complex)
   if (octave::math::isnan (x))
     octave::err_nan_to_logical_conversion ();
 
-  return octave_value (x == 0.0);
+  return octave_value_factory::make (x == 0.0);
 }
 
-DEFUNOP_OP (uplus, complex, /* no-op */)
-DEFUNOP_OP (uminus, complex, -)
-DEFUNOP_OP (transpose, complex, /* no-op */)
+DEFUNOP_SCALAR_OP (uplus, complex, /* no-op */)
+DEFUNOP_SCALAR_OP (uminus, complex, -)
+DEFUNOP_SCALAR_OP (transpose, complex, /* no-op */)
 
 DEFUNOP (hermitian, complex)
 {
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v, a);
 
-  return octave_value (conj (v.complex_value ()));
+  return octave_value_factory::make (conj (v.octave_complex::complex_value ()));
 }
 
 DEFNCUNOP_METHOD (incr, complex, increment)
@@ -70,26 +70,28 @@ DEFNCUNOP_METHOD (decr, complex, decreme
 
 // complex scalar by complex scalar ops.
 
-DEFBINOP_OP (add, complex, complex, +)
-DEFBINOP_OP (sub, complex, complex, -)
-DEFBINOP_OP (mul, complex, complex, *)
+DEFBINOP_SCALAR_OP (add, complex, complex, +)
+DEFBINOP_SCALAR_OP (sub, complex, complex, -)
+DEFBINOP_SCALAR_OP (mul, complex, complex, *)
 
 DEFBINOP (div, complex, complex)
 {
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v2, a2);
 
-  return octave_value (v1.complex_value () / v2.complex_value ());
+  return octave_value_factory::make (v1.octave_complex::complex_value () /
+                                     v2.octave_complex::complex_value ());
 }
 
-DEFBINOP_FN (pow, complex, complex, xpow)
+DEFBINOP_SCALAR_FN (pow, complex, complex, xpow)
 
 DEFBINOP (ldiv, complex, complex)
 {
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v2, a2);
 
-  return octave_value (v2.complex_value () / v1.complex_value ());
+  return octave_value_factory::make (v2.octave_complex::complex_value () /
+                                     v1.octave_complex::complex_value ());
 }
 
 DEFCMPLXCMPOP_OP (lt, complex, complex, <)
@@ -99,24 +101,26 @@ DEFCMPLXCMPOP_OP (ge, complex, complex, 
 DEFCMPLXCMPOP_OP (gt, complex, complex, >)
 DEFCMPLXCMPOP_OP (ne, complex, complex, !=)
 
-DEFBINOP_OP (el_mul, complex, complex, *)
+DEFBINOP_SCALAR_OP (el_mul, complex, complex, *)
 
 DEFBINOP (el_div, complex, complex)
 {
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v2, a2);
 
-  return octave_value (v1.complex_value () / v2.complex_value ());
+  return octave_value_factory::make (v1.octave_complex::complex_value () /
+                                     v2.octave_complex::complex_value ());
 }
 
-DEFBINOP_FN (el_pow, complex, complex, xpow)
+DEFBINOP_SCALAR_FN (el_pow, complex, complex, xpow)
 
 DEFBINOP (el_ldiv, complex, complex)
 {
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v2, a2);
 
-  return octave_value (v2.complex_value () / v1.complex_value ());
+  return octave_value_factory::make (v2.octave_complex::complex_value () /
+                                     v1.octave_complex::complex_value ());
 }
 
 DEFBINOP (el_and, complex, complex)
@@ -124,7 +128,8 @@ DEFBINOP (el_and, complex, complex)
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v2, a2);
 
-  return v1.complex_value () != 0.0 && v2.complex_value () != 0.0;
+  return v1.octave_complex::complex_value () != 0.0 &&
+    v2.octave_complex::complex_value () != 0.0;
 }
 
 DEFBINOP (el_or, complex, complex)
@@ -132,7 +137,8 @@ DEFBINOP (el_or, complex, complex)
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v2, a2);
 
-  return v1.complex_value () != 0.0 || v2.complex_value () != 0.0;
+  return v1.octave_complex::complex_value () != 0.0 ||
+    v2.octave_complex::complex_value () != 0.0;
 }
 
 DEFNDCATOP_FN (cs_cs, complex, complex, complex_array, complex_array, concat)
diff -r 435878fa6d33 libinterp/operators/op-cs-s.cc
--- a/libinterp/operators/op-cs-s.cc	Tue Feb 28 19:34:27 2023 -0500
+++ b/libinterp/operators/op-cs-s.cc	Wed Mar 01 09:13:22 2023 -0500
@@ -41,26 +41,28 @@ OCTAVE_BEGIN_NAMESPACE(octave)
 
 // complex scalar by scalar ops.
 
-DEFBINOP_OP (add, complex, scalar, +)
-DEFBINOP_OP (sub, complex, scalar, -)
-DEFBINOP_OP (mul, complex, scalar, *)
+DEFBINOP_SCALAR_OP (add, complex, scalar, +)
+DEFBINOP_SCALAR_OP (sub, complex, scalar, -)
+DEFBINOP_SCALAR_OP (mul, complex, scalar, *)
 
 DEFBINOP (div, complex, scalar)
 {
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_scalar&, v2, a2);
 
-  return octave_value (v1.complex_value () / v2.double_value ());
+  return octave_value_factory::make (v1.octave_complex::complex_value () /
+                                     v2.octave_scalar::double_value ());
 }
 
-DEFBINOP_FN (pow, complex, scalar, xpow)
+DEFBINOP_SCALAR_FN (pow, complex, scalar, xpow)
 
 DEFBINOP (ldiv, complex, scalar)
 {
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_scalar&, v2, a2);
 
-  return octave_value (v2.double_value () / v1.complex_value ());
+  return octave_value_factory::make (v2.octave_scalar::double_value () /
+                                     v1.octave_complex::complex_value ());
 }
 
 DEFCMPLXCMPOP_OP (lt, complex, scalar, <)
@@ -70,24 +72,26 @@ DEFCMPLXCMPOP_OP (ge, complex, scalar, >
 DEFCMPLXCMPOP_OP (gt, complex, scalar, >)
 DEFCMPLXCMPOP_OP (ne, complex, scalar, !=)
 
-DEFBINOP_OP (el_mul, complex, scalar, *)
+DEFBINOP_SCALAR_OP (el_mul, complex, scalar, *)
 
 DEFBINOP (el_div, complex, scalar)
 {
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_scalar&, v2, a2);
 
-  return octave_value (v1.complex_value () / v2.double_value ());
+  return octave_value_factory::make (v1.octave_complex::complex_value () /
+                                     v2.octave_scalar::double_value ());
 }
 
-DEFBINOP_FN (el_pow, complex, scalar, xpow)
+DEFBINOP_SCALAR_FN (el_pow, complex, scalar, xpow)
 
 DEFBINOP (el_ldiv, complex, scalar)
 {
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_scalar&, v2, a2);
 
-  return octave_value (v2.double_value () / v1.complex_value ());
+  return octave_value_factory::make (v2.octave_scalar::double_value () /
+                                     v1.octave_complex::complex_value ());
 }
 
 DEFBINOP (el_and, complex, scalar)
@@ -95,7 +99,8 @@ DEFBINOP (el_and, complex, scalar)
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_scalar&, v2, a2);
 
-  return v1.complex_value () != 0.0 && v2.double_value ();
+  return v1.octave_complex::complex_value () != 0.0 &&
+    v2.octave_scalar::double_value ();
 }
 
 DEFBINOP (el_or, complex, scalar)
@@ -103,7 +108,8 @@ DEFBINOP (el_or, complex, scalar)
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_scalar&, v2, a2);
 
-  return v1.complex_value () != 0.0 || v2.double_value ();
+  return v1.octave_complex::complex_value () != 0.0 ||
+    v2.octave_scalar::double_value ();
 }
 
 DEFNDCATOP_FN (cs_s, complex, scalar, complex_array, array, concat)
diff -r 435878fa6d33 libinterp/operators/op-s-cs.cc
--- a/libinterp/operators/op-s-cs.cc	Tue Feb 28 19:34:27 2023 -0500
+++ b/libinterp/operators/op-s-cs.cc	Wed Mar 01 09:13:22 2023 -0500
@@ -43,26 +43,28 @@ OCTAVE_BEGIN_NAMESPACE(octave)
 
 // scalar by complex scalar ops.
 
-DEFBINOP_OP (add, scalar, complex, +)
-DEFBINOP_OP (sub, scalar, complex, -)
-DEFBINOP_OP (mul, scalar, complex, *)
+DEFBINOP_SCALAR_OP (add, scalar, complex, +)
+DEFBINOP_SCALAR_OP (sub, scalar, complex, -)
+DEFBINOP_SCALAR_OP (mul, scalar, complex, *)
 
 DEFBINOP (div, scalar, complex)
 {
   OCTAVE_CAST_BASE_VALUE (const octave_scalar&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v2, a2);
 
-  return octave_value (v1.double_value () / v2.complex_value ());
+  return octave_value_factory::make (v1.octave_scalar::double_value () /
+                                     v2.octave_complex::complex_value ());
 }
 
-DEFBINOP_FN (pow, scalar, complex, xpow)
+DEFBINOP_SCALAR_FN (pow, scalar, complex, xpow)
 
 DEFBINOP (ldiv, scalar, complex)
 {
   OCTAVE_CAST_BASE_VALUE (const octave_scalar&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v2, a2);
 
-  return octave_value (v2.complex_value () / v1.double_value ());
+  return octave_value_factory::make (v2.octave_complex::complex_value () /
+                                     v1.octave_scalar::double_value ());
 }
 
 DEFCMPLXCMPOP_OP (lt, scalar, complex, <)
@@ -72,24 +74,26 @@ DEFCMPLXCMPOP_OP (ge, scalar, complex, >
 DEFCMPLXCMPOP_OP (gt, scalar, complex, >)
 DEFCMPLXCMPOP_OP (ne, scalar, complex, !=)
 
-DEFBINOP_OP (el_mul, scalar, complex, *)
+DEFBINOP_SCALAR_OP (el_mul, scalar, complex, *)
 
 DEFBINOP (el_div, scalar, complex)
 {
   OCTAVE_CAST_BASE_VALUE (const octave_scalar&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v2, a2);
 
-  return octave_value (v1.double_value () / v2.complex_value ());
+  return octave_value_factory::make (v1.octave_scalar::double_value () /
+                                     v2.octave_complex::complex_value ());
 }
 
-DEFBINOP_FN (el_pow, scalar, complex, xpow)
+DEFBINOP_SCALAR_FN (el_pow, scalar, complex, xpow)
 
 DEFBINOP (el_ldiv, scalar, complex)
 {
   OCTAVE_CAST_BASE_VALUE (const octave_scalar&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v2, a2);
 
-  return octave_value (v2.complex_value () / v1.double_value ());
+  return octave_value_factory::make (v2.octave_complex::complex_value () /
+                                     v1.octave_scalar::double_value ());
 }
 
 DEFBINOP (el_and, scalar, complex)
@@ -97,7 +101,9 @@ DEFBINOP (el_and, scalar, complex)
   OCTAVE_CAST_BASE_VALUE (const octave_scalar&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v2, a2);
 
-  return octave_value (v1.double_value () && (v2.complex_value () != 0.0));
+  return octave_value_factory::make (
+    v1.octave_scalar::double_value () &&
+    (v2.octave_complex::complex_value () != 0.0));
 }
 
 DEFBINOP (el_or, scalar, complex)
@@ -105,7 +111,9 @@ DEFBINOP (el_or, scalar, complex)
   OCTAVE_CAST_BASE_VALUE (const octave_scalar&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_complex&, v2, a2);
 
-  return octave_value (v1.double_value () || (v2.complex_value () != 0.0));
+  return octave_value_factory::make (
+    v1.octave_scalar::double_value () ||
+    (v2.octave_complex::complex_value () != 0.0));
 }
 
 DEFNDCATOP_FN (s_cs, scalar, complex, array, complex_array, concat)
diff -r 435878fa6d33 libinterp/operators/op-s-s.cc
--- a/libinterp/operators/op-s-s.cc	Tue Feb 28 19:34:27 2023 -0500
+++ b/libinterp/operators/op-s-s.cc	Wed Mar 01 09:13:22 2023 -0500
@@ -52,66 +52,70 @@ DEFUNOP (not, scalar)
   if (octave::math::isnan (x))
     octave::err_nan_to_logical_conversion ();
 
-  return octave_value (x == 0.0);
+  return octave_value_factory::make (x == 0.0);
 }
 
-DEFUNOP_OP (uplus, scalar, /* no-op */)
-DEFUNOP_OP (uminus, scalar, -)
-DEFUNOP_OP (transpose, scalar, /* no-op */)
-DEFUNOP_OP (hermitian, scalar, /* no-op */)
+DEFUNOP_SCALAR_OP (uplus, scalar, /* no-op */)
+DEFUNOP_SCALAR_OP (uminus, scalar, -)
+DEFUNOP_SCALAR_OP (transpose, scalar, /* no-op */)
+DEFUNOP_SCALAR_OP (hermitian, scalar, /* no-op */)
 
 DEFNCUNOP_METHOD (incr, scalar, increment)
 DEFNCUNOP_METHOD (decr, scalar, decrement)
 
 // scalar by scalar ops.
 
-DEFBINOP_OP (add, scalar, scalar, +)
-DEFBINOP_OP (sub, scalar, scalar, -)
-DEFBINOP_OP (mul, scalar, scalar, *)
+DEFBINOP_SCALAR_OP (add, scalar, scalar, +)
+DEFBINOP_SCALAR_OP (sub, scalar, scalar, -)
+DEFBINOP_SCALAR_OP (mul, scalar, scalar, *)
 
 DEFBINOP (div, scalar, scalar)
 {
   OCTAVE_CAST_BASE_VALUE (const octave_scalar&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_scalar&, v2, a2);
 
-  return octave_value (v1.double_value () / v2.double_value ());
+  return octave_value_factory::make (v1.octave_scalar::double_value () /
+                                     v2.octave_scalar::double_value ());
 }
 
-DEFBINOP_FN (pow, scalar, scalar, xpow)
+DEFBINOP_SCALAR_FN (pow, scalar, scalar, xpow)
 
 DEFBINOP (ldiv, scalar, scalar)
 {
   OCTAVE_CAST_BASE_VALUE (const octave_scalar&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_scalar&, v2, a2);
 
-  return octave_value (v2.double_value () / v1.double_value ());
+  return octave_value_factory::make (v2.octave_scalar::double_value () /
+                                     v1.octave_scalar::double_value ());
 }
 
-DEFBINOP_OP (lt, scalar, scalar, <)
-DEFBINOP_OP (le, scalar, scalar, <=)
-DEFBINOP_OP (eq, scalar, scalar, ==)
-DEFBINOP_OP (ge, scalar, scalar, >=)
-DEFBINOP_OP (gt, scalar, scalar, >)
-DEFBINOP_OP (ne, scalar, scalar, !=)
+DEFBINOP_SCALAR_OP (lt, scalar, scalar, <)
+DEFBINOP_SCALAR_OP (le, scalar, scalar, <=)
+DEFBINOP_SCALAR_OP (eq, scalar, scalar, ==)
+DEFBINOP_SCALAR_OP (ge, scalar, scalar, >=)
+DEFBINOP_SCALAR_OP (gt, scalar, scalar, >)
+DEFBINOP_SCALAR_OP (ne, scalar, scalar, !=)
 
-DEFBINOP_OP (el_mul, scalar, scalar, *)
+DEFBINOP_SCALAR_OP (el_mul, scalar, scalar, *)
 
 DEFBINOP (el_div, scalar, scalar)
 {
   OCTAVE_CAST_BASE_VALUE (const octave_scalar&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_scalar&, v2, a2);
 
-  return octave_value (v1.double_value () / v2.double_value ());
+  return octave_value_factory::make (v1.octave_scalar::double_value () /
+                                     v2.octave_scalar::double_value ());
 }
 
-DEFBINOP_FN (el_pow, scalar, scalar, xpow)
+DEFBINOP_SCALAR_FN (el_pow, scalar, scalar, xpow)
 
 DEFBINOP (el_ldiv, scalar, scalar)
 {
   OCTAVE_CAST_BASE_VALUE (const octave_scalar&, v1, a1);
   OCTAVE_CAST_BASE_VALUE (const octave_scalar&, v2, a2);
 
-  return octave_value (v2.double_value () / v1.double_value ());
+  return octave_value_factory::make (v2.octave_scalar::double_value () /
+                                     v1.octave_scalar::double_value ());
 }
 
 DEFSCALARBOOLOP_OP (el_and, scalar, scalar, &&)
diff -r 435878fa6d33 libinterp/operators/ops.h
--- a/libinterp/operators/ops.h	Tue Feb 28 19:34:27 2023 -0500
+++ b/libinterp/operators/ops.h	Wed Mar 01 09:13:22 2023 -0500
@@ -30,6 +30,7 @@
 
 #include "Array-util.h"
 #include "error.h"
+#include "ov-inline.h"
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
@@ -203,6 +204,16 @@ OCTAVE_END_NAMESPACE(octave)
     return octave_value (op v.CONCAT2 (t, _value) ());          \
   }
 
+#define DEFUNOP_SCALAR_OP(name, t, op)                                      \
+  static octave_value CONCAT2(oct_unop_, name)(const octave_base_value &a)  \
+    {                                                                       \
+      const CONCAT2(octave_, t) &v =                                        \
+          OCTAVE_DYNAMIC_CAST<const CONCAT2(octave_, t) &>(a);                   \
+      return octave_value_factory::make                                     \
+        (op v.CONCAT2 (octave_, t)::CONCAT2 (t, _value) ());                \
+    }
+
+
 #define DEFNDUNOP_OP(name, t, e, op)                            \
   static octave_value                                           \
   CONCAT2 (oct_unop_, name) (const octave_base_value& a)        \
@@ -234,7 +245,7 @@ OCTAVE_END_NAMESPACE(octave)
   CONCAT2 (oct_unop_, name) (octave_base_value& a)              \
   {                                                             \
     OCTAVE_CAST_BASE_VALUE (CONCAT2 (octave_, t)&, v, a);       \
-    v.method ();                                                \
+    v.CONCAT2 (octave_, t)::method ();                          \
   }
 
 #define DEFBINOPX(name, t1, t2)                         \
@@ -247,6 +258,19 @@ OCTAVE_END_NAMESPACE(octave)
   CONCAT2 (oct_binop_, name) (const octave_base_value& a1,      \
                               const octave_base_value& a2)
 
+#define DEFBINOP_SCALAR_OP(name, t1, t2, op)                               \
+  static octave_value CONCAT2(oct_binop_, name)(const octave_base_value &a1,   \
+                                                const octave_base_value &a2) { \
+    const CONCAT2(octave_, t1) &v1 =                                           \
+        OCTAVE_DYNAMIC_CAST<const CONCAT2(octave_, t1) &>(a1);                      \
+    const CONCAT2(octave_, t2) &v2 =                                           \
+        OCTAVE_DYNAMIC_CAST<const CONCAT2(octave_, t2) &>(a2);                      \
+    /* Note: Not virtual calls */                                              \
+    return octave_value_factory::make                                          \
+      (v1.CONCAT2(octave_, t1)::CONCAT2(t1, _value)() op               \
+       v2.CONCAT2(octave_, t2)::CONCAT2(t2, _value)());                \
+  }
+
 #define DEFBINOP_OP(name, t1, t2, op)                                   \
   static octave_value                                                   \
   CONCAT2 (oct_binop_, name) (const octave_base_value& a1,              \
@@ -268,9 +292,10 @@ OCTAVE_END_NAMESPACE(octave)
     OCTAVE_CAST_BASE_VALUE (const CONCAT2 (octave_, t2)&, v2, a2);      \
                                                                         \
     warn_complex_cmp ();                                                \
-                                                                        \
-    return octave_value                                                 \
-      (v1.CONCAT2 (t1, _value) () op v2.CONCAT2 (t2, _value) ());       \
+    /* Note: Not virtual call */                                        \
+    return octave_value_factory::make                                   \
+      (v1.CONCAT2 (octave_, t1)::CONCAT2 (t1, _value) () op             \
+       v2.CONCAT2 (octave_, t2)::CONCAT2 (t2, _value) ());              \
   }
 
 #define DEFSCALARBOOLOP_OP(name, t1, t2, op)                            \
@@ -284,8 +309,9 @@ OCTAVE_END_NAMESPACE(octave)
     if (octave::math::isnan (v1.CONCAT2 (t1, _value) ()) || octave::math::isnan (v2.CONCAT2 (t2, _value) ())) \
       octave::err_nan_to_logical_conversion ();                         \
                                                                         \
-    return octave_value                                                 \
-      (v1.CONCAT2 (t1, _value) () op v2.CONCAT2 (t2, _value) ());       \
+    return octave_value_factory::make                                   \
+      (v1.CONCAT2 (octave_, t1)::CONCAT2 (t1, _value) () op             \
+       v2.CONCAT2 (octave_, t2)::CONCAT2 (t2, _value) ());    \
   }
 
 #define DEFNDBINOP_OP(name, t1, t2, e1, e2, op)                         \
@@ -313,6 +339,19 @@ OCTAVE_END_NAMESPACE(octave)
     return octave_value (f (v1.CONCAT2 (t1, _value) (), v2.CONCAT2 (t2, _value) ())); \
   }
 
+#define DEFBINOP_SCALAR_FN(name, t1, t2, f)                             \
+  static octave_value                                                   \
+  CONCAT2 (oct_binop_, name) (const octave_base_value& a1,              \
+                              const octave_base_value& a2)              \
+  {                                                                     \
+    const CONCAT2 (octave_, t1)& v1 = OCTAVE_DYNAMIC_CAST<const CONCAT2 (octave_, t1)&> (a1); \
+    const CONCAT2 (octave_, t2)& v2 = OCTAVE_DYNAMIC_CAST<const CONCAT2 (octave_, t2)&> (a2); \
+                                                                        \
+    return octave_value (                                               \
+      f (v1.CONCAT2 (octave_, t1)::CONCAT2 (t1, _value) (),             \
+         v2.CONCAT2 (octave_, t2)::CONCAT2 (t2, _value) ()));    \
+  }
+
 #define DEFNDBINOP_FN(name, t1, t2, e1, e2, f)                          \
   static octave_value                                                   \
   CONCAT2 (oct_binop_, name) (const octave_base_value& a1,              \
