Repository: scikit-hep/awkward

Issue:
`ak.ArrayBuilder` loses behaviour through `ak._util.behaviorof`
### Version of Awkward Array

main

### Description and code to reproduce

```python
import awkward as ak

class Point:
    def length(self):
        raise NotImplementedError

behavior = {
    ('*', 'point'): Point
}
builder = ak.ArrayBuilder(behavior=behavior)
with builder.record("Point"):
	builder.field("x").real(1.0)
	builder.field("y").real(2.0)
	builder.field("z").real(3.0)

assert ak._util.arrays_approx_equal(builder, builder.snapshot())


Discussion:

Resolving patch:
diff --git a/src/awkward/_util.py b/src/awkward/_util.py
--- a/src/awkward/_util.py
+++ b/src/awkward/_util.py
@@ -410,7 +410,7 @@ def behavior_of(*arrays, **kwargs):
     highs = (
         ak.highlevel.Array,
         ak.highlevel.Record,
-        # ak.highlevel.ArrayBuilder,
+        ak.highlevel.ArrayBuilder,
     )
     for x in arrays[::-1]:
         if isinstance(x, highs) and x.behavior is not None:
@@ -859,8 +859,8 @@ def arrays_approx_equal(
 
     import awkward.forms.form
 
-    left_behavior = ak._util.behavior_of(left, behavior=ak.behavior)
-    right_behavior = ak._util.behavior_of(right, behavior=ak.behavior)
+    left_behavior = ak._util.behavior_of(left)
+    right_behavior = ak._util.behavior_of(right)
 
     left = ak.to_packed(ak.to_layout(left, allow_record=False), highlevel=False)
     right = ak.to_packed(ak.to_layout(right, allow_record=False), highlevel=False)
@@ -890,13 +890,9 @@ def visitor(left, right) -> bool:
         ):
             return False
 
-        # Allow an `__array__` to be set with no value in `ak.behavior`;
-        # this is sometimes useful in testing. What we _don't_ want is for one
-        # array to have a behavior class and another to lack it.
-        array = left.parameter("__array__")
+        # Require that the arrays have the same evaluated types
         if not (
-            array is None
-            or (left_behavior.get(array) is right_behavior.get(array))
+            arrayclass(left, left_behavior) is arrayclass(right, right_behavior)
             or not check_parameters
         ):
             return False
@@ -923,11 +919,10 @@ def visitor(left, right) -> bool:
                 ]
             )
         elif left.is_record:
-            record = left.parameter("__record__")
             return (
                 (
-                    record is None
-                    or (left_behavior.get(record) is right_behavior.get(record))
+                    recordclass(left, left_behavior)
+                    is recordclass(right, right_behavior)
                     or not check_parameters
                 )
                 and (left.fields == right.fields)


Test patch:
diff --git a/tests/test_2051_arraybuilder_behavior_propagation.py b/tests/test_2051_arraybuilder_behavior_propagation.py
new file mode 100644
--- /dev/null
+++ b/tests/test_2051_arraybuilder_behavior_propagation.py
@@ -0,0 +1,17 @@
+import awkward as ak
+
+
+class Point(ak.Array):
+    def length(self):
+        raise NotImplementedError
+
+
+def test():
+    behavior = {("*", "point"): Point}
+    builder = ak.ArrayBuilder(behavior=behavior)
+    with builder.record("point"):
+        builder.field("x").real(1.0)
+        builder.field("y").real(2.0)
+        builder.field("z").real(3.0)
+
+    assert ak._util.arrays_approx_equal(builder, builder.snapshot())