[ASTERIXDB-3446][RT] Use VoidPointable instead of IVisitablePointable

- user model changes: no
- storage format changes: no
- interface changes: no

Details:
For the result pointable of the cast(), Use VoidPointable instead of
IVisitablePointable to avoid unnecessary objects creation when
set() is called by the result pointable.

Change-Id: Ie1006b20fb9d7fbd6e4c0f04e67b0e14d85116f5
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/18404
Reviewed-by: Ali Alsuliman <ali.al.solaiman@gmail.com>
Reviewed-by: Wail Alkowaileet <wael.y.k@gmail.com>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Ali Alsuliman <ali.al.solaiman@gmail.com>
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/om/lazy/LazyVisitablePointableTest.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/om/lazy/LazyVisitablePointableTest.java
index d981be1..d6cf026 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/om/lazy/LazyVisitablePointableTest.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/om/lazy/LazyVisitablePointableTest.java
@@ -29,12 +29,10 @@
 import org.apache.asterix.om.lazy.TypedRecordLazyVisitablePointable;
 import org.apache.asterix.om.pointables.ARecordVisitablePointable;
 import org.apache.asterix.om.pointables.base.DefaultOpenFieldType;
-import org.apache.asterix.om.pointables.base.IVisitablePointable;
 import org.apache.asterix.om.pointables.cast.ACastVisitor;
+import org.apache.asterix.om.pointables.cast.CastResult;
 import org.apache.asterix.om.types.ARecordType;
-import org.apache.asterix.om.types.IAType;
 import org.apache.asterix.runtime.evaluators.comparisons.DeepEqualAssessor;
-import org.apache.hyracks.algebricks.common.utils.Triple;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
 import org.junit.Assert;
@@ -55,7 +53,7 @@
     private final RecordLazyVisitablePointable openLazyPointable;
     private final ARecordVisitablePointable openPointable;
     private final ArrayBackedValueStorage recordStorage;
-    private final Triple<IVisitablePointable, IAType, Boolean> arg;
+    private final CastResult castResult;
 
     static {
         BASE_DIR = "data";
@@ -74,8 +72,7 @@
         openLazyPointable = new RecordLazyVisitablePointable(true);
         openPointable = new ARecordVisitablePointable(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE);
         recordStorage = new ArrayBackedValueStorage();
-        arg = new Triple<>(null, null, null);
-        arg.third = Boolean.FALSE;
+        castResult = new CastResult(null, null);
     }
 
     private void prepareParser(String path) throws IOException {
@@ -91,12 +88,12 @@
             //Infer the schema
             ARecordType inferredFromOpen = (ARecordType) openLazyPointable.accept(schemaInference, "fromOpen");
             ARecordVisitablePointable closedPointable = new ARecordVisitablePointable(inferredFromOpen);
-            arg.first = closedPointable;
-            arg.second = inferredFromOpen;
+            castResult.setOutPointable(closedPointable);
+            castResult.setOutType(inferredFromOpen);
 
             //Cast to closed using the inferred type
             openPointable.set(recordStorage);
-            openPointable.accept(castVisitor, arg);
+            openPointable.accept(castVisitor, castResult);
             //Ensure both closed and open records are the same
             Assert.assertTrue(deepEqualAssessor.isEqual(openPointable, closedPointable));
 
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ACastVisitor.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ACastVisitor.java
index 993edee..2dd7bfe 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ACastVisitor.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ACastVisitor.java
@@ -37,9 +37,9 @@
 import org.apache.asterix.om.types.EnumDeserializer;
 import org.apache.asterix.om.types.IAType;
 import org.apache.asterix.om.types.hierachy.ATypeHierarchy;
-import org.apache.hyracks.algebricks.common.utils.Triple;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.api.exceptions.SourceLocation;
+import org.apache.hyracks.data.std.api.IPointable;
 import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
 
 /**
@@ -53,7 +53,7 @@
  * memory/storage layout, the visitor will change the layout as specified at
  * runtime.
  */
-public class ACastVisitor implements IVisitablePointableVisitor<Void, Triple<IVisitablePointable, IAType, Boolean>> {
+public class ACastVisitor implements IVisitablePointableVisitor<Void, CastResult> {
 
     private final Map<IVisitablePointable, ARecordCaster> raccessorToCaster = new HashMap<>();
     private final Map<IVisitablePointable, AListCaster> laccessorToCaster = new HashMap<>();
@@ -76,8 +76,7 @@
     }
 
     @Override
-    public Void visit(AListVisitablePointable accessor, Triple<IVisitablePointable, IAType, Boolean> arg)
-            throws HyracksDataException {
+    public Void visit(AListVisitablePointable accessor, CastResult castResult) throws HyracksDataException {
         AListCaster caster = laccessorToCaster.get(accessor);
         if (caster == null) {
             caster = new AListCaster();
@@ -85,27 +84,26 @@
         }
 
         AbstractCollectionType resultType;
-        switch (arg.second.getTypeTag()) {
+        switch (castResult.getOutType().getTypeTag()) {
             case ANY:
                 resultType = accessor.ordered() ? DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE
                         : DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE;
                 break;
             case ARRAY:
             case MULTISET:
-                resultType = (AbstractCollectionType) arg.second;
+                resultType = (AbstractCollectionType) castResult.getOutType();
                 break;
             default:
                 throw new RuntimeDataException(ErrorCode.TYPE_CONVERT, sourceLoc,
-                        accessor.ordered() ? ATypeTag.ARRAY : ATypeTag.MULTISET, arg.second.getTypeTag());
+                        accessor.ordered() ? ATypeTag.ARRAY : ATypeTag.MULTISET, castResult.getOutType().getTypeTag());
         }
 
-        caster.castList(accessor, arg.first, resultType, this);
+        caster.castList(accessor, castResult.getOutPointable(), resultType, this);
         return null;
     }
 
     @Override
-    public Void visit(ARecordVisitablePointable accessor, Triple<IVisitablePointable, IAType, Boolean> arg)
-            throws HyracksDataException {
+    public Void visit(ARecordVisitablePointable accessor, CastResult castResult) throws HyracksDataException {
         ARecordCaster caster = raccessorToCaster.get(accessor);
         if (caster == null) {
             caster = new ARecordCaster();
@@ -113,47 +111,48 @@
         }
 
         ARecordType resultType;
-        switch (arg.second.getTypeTag()) {
+        IAType oType = castResult.getOutType();
+        switch (oType.getTypeTag()) {
             case ANY:
                 resultType = DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE;
                 break;
             case OBJECT:
-                resultType = (ARecordType) arg.second;
+                resultType = (ARecordType) oType;
                 break;
             default:
-                throw new RuntimeDataException(ErrorCode.TYPE_CONVERT, sourceLoc, ATypeTag.OBJECT,
-                        arg.second.getTypeTag());
+                throw new RuntimeDataException(ErrorCode.TYPE_CONVERT, sourceLoc, ATypeTag.OBJECT, oType.getTypeTag());
         }
 
-        caster.castRecord(accessor, arg.first, resultType, this);
+        caster.castRecord(accessor, castResult.getOutPointable(), resultType, this);
         return null;
     }
 
     @Override
-    public Void visit(AFlatValuePointable accessor, Triple<IVisitablePointable, IAType, Boolean> arg)
-            throws HyracksDataException {
-        if (arg.second == null) {
+    public Void visit(AFlatValuePointable accessor, CastResult castResult) throws HyracksDataException {
+        IAType oType = castResult.getOutType();
+        IPointable outPointable = castResult.getOutPointable();
+        if (oType == null) {
             // for open type case
-            arg.first.set(accessor);
+            outPointable.set(accessor);
             return null;
         }
         // set the pointer for result
-        ATypeTag reqTypeTag = (arg.second).getTypeTag();
+        ATypeTag reqTypeTag = oType.getTypeTag();
         if (reqTypeTag == ATypeTag.ANY) {
             // for open type case
-            arg.first.set(accessor);
+            outPointable.set(accessor);
             return null;
         }
         ATypeTag inputTypeTag =
                 EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(accessor.getByteArray()[accessor.getStartOffset()]);
         if (!needPromote(inputTypeTag, reqTypeTag)) {
-            arg.first.set(accessor);
+            outPointable.set(accessor);
         } else {
             try {
                 castBuffer.reset();
                 ATypeHierarchy.convertNumericTypeByteArray(accessor.getByteArray(), accessor.getStartOffset(),
                         accessor.getLength(), reqTypeTag, castBuffer.getDataOutput(), strictDemote);
-                arg.first.set(castBuffer);
+                outPointable.set(castBuffer);
             } catch (HyracksDataException e) {
                 throw e;
             } catch (IOException e) {
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/AListCaster.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/AListCaster.java
index 492a9d3..96c7db1 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/AListCaster.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/AListCaster.java
@@ -26,7 +26,6 @@
 import org.apache.asterix.builders.OrderedListBuilder;
 import org.apache.asterix.builders.UnorderedListBuilder;
 import org.apache.asterix.om.pointables.AListVisitablePointable;
-import org.apache.asterix.om.pointables.PointableAllocator;
 import org.apache.asterix.om.pointables.base.DefaultOpenFieldType;
 import org.apache.asterix.om.pointables.base.IVisitablePointable;
 import org.apache.asterix.om.types.ATypeTag;
@@ -34,8 +33,9 @@
 import org.apache.asterix.om.types.EnumDeserializer;
 import org.apache.asterix.om.types.IAType;
 import org.apache.asterix.om.utils.ResettableByteArrayOutputStream;
-import org.apache.hyracks.algebricks.common.utils.Triple;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.api.IPointable;
+import org.apache.hyracks.data.std.primitive.VoidPointable;
 
 /**
  * This class is to do the runtime type cast for a list. It is ONLY visible to
@@ -43,20 +43,15 @@
  */
 class AListCaster {
 
-    // for storing the cast result
-    private final IVisitablePointable itemTempReference = PointableAllocator.allocateUnrestableEmpty();
-    private final Triple<IVisitablePointable, IAType, Boolean> itemVisitorArg =
-            new Triple<>(itemTempReference, null, null);
-
+    private final CastResult itemCastResult = new CastResult(new VoidPointable(), null);
     private final UnorderedListBuilder unOrderedListBuilder = new UnorderedListBuilder();
     private final OrderedListBuilder orderedListBuilder = new OrderedListBuilder();
-
     private final ResettableByteArrayOutputStream dataBos = new ResettableByteArrayOutputStream();
     private final DataOutput dataDos = new DataOutputStream(dataBos);
     private IAType reqItemType;
 
-    public void castList(AListVisitablePointable listAccessor, IVisitablePointable resultAccessor,
-            AbstractCollectionType reqType, ACastVisitor visitor) throws HyracksDataException {
+    public void castList(AListVisitablePointable listAccessor, IPointable castOutResult, AbstractCollectionType reqType,
+            ACastVisitor visitor) throws HyracksDataException {
         if (reqType.getTypeTag().equals(ATypeTag.MULTISET)) {
             unOrderedListBuilder.reset(reqType);
             reqItemType = reqType.getItemType();
@@ -77,16 +72,16 @@
             ATypeTag typeTag = EnumDeserializer.ATYPETAGDESERIALIZER
                     .deserialize(itemTypeTag.getByteArray()[itemTypeTag.getStartOffset()]);
             if (reqItemType == null || reqItemType.getTypeTag().equals(ATypeTag.ANY)) {
-                itemVisitorArg.second = DefaultOpenFieldType.getDefaultOpenFieldType(typeTag);
+                itemCastResult.setOutType(DefaultOpenFieldType.getDefaultOpenFieldType(typeTag));
             } else {
-                itemVisitorArg.second = reqItemType;
+                itemCastResult.setOutType(reqItemType);
             }
-            item.accept(visitor, itemVisitorArg);
+            item.accept(visitor, itemCastResult);
             if (reqType.getTypeTag().equals(ATypeTag.ARRAY)) {
-                orderedListBuilder.addItem(itemVisitorArg.first);
+                orderedListBuilder.addItem(itemCastResult.getOutPointable());
             }
             if (reqType.getTypeTag().equals(ATypeTag.MULTISET)) {
-                unOrderedListBuilder.addItem(itemVisitorArg.first);
+                unOrderedListBuilder.addItem(itemCastResult.getOutPointable());
             }
         }
         if (reqType.getTypeTag().equals(ATypeTag.ARRAY)) {
@@ -96,6 +91,6 @@
             unOrderedListBuilder.write(dataDos, true);
         }
         int end = dataBos.size();
-        resultAccessor.set(dataBos.getByteArray(), start, end - start);
+        castOutResult.set(dataBos.getByteArray(), start, end - start);
     }
 }
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ARecordCaster.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ARecordCaster.java
index c6e1423..6dda563 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ARecordCaster.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ARecordCaster.java
@@ -45,11 +45,12 @@
 import org.apache.asterix.om.utils.NonTaggedFormatUtil;
 import org.apache.asterix.om.utils.ResettableByteArrayOutputStream;
 import org.apache.hyracks.algebricks.common.utils.Pair;
-import org.apache.hyracks.algebricks.common.utils.Triple;
 import org.apache.hyracks.api.dataflow.value.IBinaryComparator;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.data.std.accessors.UTF8StringBinaryComparatorFactory;
+import org.apache.hyracks.data.std.api.IPointable;
 import org.apache.hyracks.data.std.api.IValueReference;
+import org.apache.hyracks.data.std.primitive.VoidPointable;
 import org.apache.hyracks.data.std.util.ByteArrayAccessibleOutputStream;
 import org.apache.hyracks.util.string.UTF8StringWriter;
 
@@ -73,9 +74,7 @@
             UTF8StringBinaryComparatorFactory.INSTANCE.createBinaryComparator();
     private final ByteArrayAccessibleOutputStream outputBos = new ByteArrayAccessibleOutputStream();
     private final DataOutputStream outputDos = new DataOutputStream(outputBos);
-    private final IVisitablePointable fieldTempReference = PointableAllocator.allocateUnrestableEmpty();
-    private final Triple<IVisitablePointable, IAType, Boolean> nestedVisitorArg =
-            new Triple<>(fieldTempReference, null, null);
+    private final CastResult fieldCastResult = new CastResult(new VoidPointable(), null);
     private int numInputFields = 0;
     // describe closed fields in the required type
     private int[] fieldPermutation;
@@ -102,8 +101,8 @@
         }
     }
 
-    public void castRecord(ARecordVisitablePointable recordAccessor, IVisitablePointable resultAccessor,
-            ARecordType reqType, ACastVisitor visitor) throws HyracksDataException {
+    public void castRecord(ARecordVisitablePointable recordAccessor, IPointable castOutResult, ARecordType reqType,
+            ACastVisitor visitor) throws HyracksDataException {
         List<IVisitablePointable> fieldNames = recordAccessor.getFieldNames();
         List<IVisitablePointable> fieldTypeTags = recordAccessor.getFieldTypeTags();
         List<IVisitablePointable> fieldValues = recordAccessor.getFieldValues();
@@ -125,7 +124,7 @@
         reset();
         matchClosedPart(fieldNames, fieldTypeTags);
         writeOutput(fieldNames, fieldTypeTags, fieldValues, outputDos, visitor);
-        resultAccessor.set(outputBos.getByteArray(), 0, outputBos.size());
+        castOutResult.set(outputBos.getByteArray(), 0, outputBos.size());
     }
 
     private void reset() {
@@ -289,7 +288,7 @@
             final int pos = fieldPermutation[i];
             final IVisitablePointable field = pos >= 0 ? fieldValues.get(pos) : missingTypeTag;
             final IAType fType = cachedReqType.getFieldTypes()[i];
-            nestedVisitorArg.second = fType;
+            fieldCastResult.setOutType(fType);
 
             // recursively casting, the result of casting can always be thought
             // as flat
@@ -297,15 +296,15 @@
                 //the field is optional in the input record
                 IVisitablePointable fieldTypeTag = pos >= 0 ? fieldTypeTags.get(pos) : null;
                 if (fieldTypeTag == null || fieldTypeTag.equals(missingTypeTag)) {
-                    nestedVisitorArg.second = BuiltinType.AMISSING;
+                    fieldCastResult.setOutType(BuiltinType.AMISSING);
                 } else if (fieldTypeTag.equals(nullTypeTag)) {
-                    nestedVisitorArg.second = BuiltinType.ANULL;
+                    fieldCastResult.setOutType(BuiltinType.ANULL);
                 } else {
-                    nestedVisitorArg.second = ((AUnionType) fType).getActualType();
+                    fieldCastResult.setOutType(((AUnionType) fType).getActualType());
                 }
             }
-            field.accept(visitor, nestedVisitorArg);
-            recBuilder.addField(i, nestedVisitorArg.first);
+            field.accept(visitor, fieldCastResult);
+            recBuilder.addField(i, fieldCastResult.getOutPointable());
         }
 
         // write the open part
@@ -317,9 +316,9 @@
 
                 ATypeTag typeTag = EnumDeserializer.ATYPETAGDESERIALIZER
                         .deserialize(fieldTypeTag.getByteArray()[fieldTypeTag.getStartOffset()]);
-                nestedVisitorArg.second = DefaultOpenFieldType.getDefaultOpenFieldType(typeTag);
-                field.accept(visitor, nestedVisitorArg);
-                recBuilder.addField(name, nestedVisitorArg.first);
+                fieldCastResult.setOutType(DefaultOpenFieldType.getDefaultOpenFieldType(typeTag));
+                field.accept(visitor, fieldCastResult);
+                recBuilder.addField(name, fieldCastResult.getOutPointable());
             }
         }
         recBuilder.write(output, true);
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/CastResult.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/CastResult.java
new file mode 100644
index 0000000..cc156aa
--- /dev/null
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/CastResult.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.asterix.om.pointables.cast;
+
+import org.apache.asterix.om.types.IAType;
+import org.apache.hyracks.data.std.api.IPointable;
+
+public class CastResult {
+
+    private IPointable outPointable;
+    private IAType outType;
+
+    public CastResult(IPointable outPointable, IAType outType) {
+        this.outPointable = outPointable;
+        this.outType = outType;
+    }
+
+    public IPointable getOutPointable() {
+        return outPointable;
+    }
+
+    public void setOutPointable(IPointable outPointable) {
+        this.outPointable = outPointable;
+    }
+
+    public IAType getOutType() {
+        return outType;
+    }
+
+    public void setOutType(IAType outType) {
+        this.outType = outType;
+    }
+}
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/aggregates/collections/ListifyAggregateFunctionEvalFactory.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/aggregates/collections/ListifyAggregateFunctionEvalFactory.java
index 838285c..2518d5d 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/aggregates/collections/ListifyAggregateFunctionEvalFactory.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/aggregates/collections/ListifyAggregateFunctionEvalFactory.java
@@ -67,7 +67,7 @@
             // create caster to open up input item if the list item type is ANY but the received item is not fully open
             private final CastTypeEvaluator caster =
                     orderedListType.getItemType().getTypeTag() == ATypeTag.ANY && !TypeHelper.isFullyOpen(itemType)
-                            ? new CastTypeEvaluator(BuiltinType.ANY, itemType, eval) : null;
+                            ? new CastTypeEvaluator(BuiltinType.ANY, itemType, eval, sourceLoc) : null;
 
             @Override
             public void init() throws HyracksDataException {
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArrayAddRemoveEval.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArrayAddRemoveEval.java
index 175ec0e..f65bf30 100755
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArrayAddRemoveEval.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArrayAddRemoveEval.java
@@ -71,7 +71,7 @@
         orderedListBuilder = null;
         unorderedListBuilder = null;
         listAccessor = new ListAccessor();
-        caster = new CastTypeEvaluator();
+        caster = new CastTypeEvaluator(null);
         storage = new ArrayBackedValueStorage();
         listArg = new VoidPointable();
         tempList = new VoidPointable();
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArrayProcessArraysEval.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArrayProcessArraysEval.java
index ddcb113..052b79d 100755
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArrayProcessArraysEval.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArrayProcessArraysEval.java
@@ -68,7 +68,7 @@
         storageAllocator = new ListObjectPool<>(ObjectFactories.STORAGE_FACTORY);
         finalResult = new ArrayBackedValueStorage();
         listAccessor = new ListAccessor();
-        caster = new CastTypeEvaluator();
+        caster = new CastTypeEvaluator(null);
         tempList = new VoidPointable();
         listsArgs = new IPointable[args.length];
         listsEval = new IScalarEvaluator[args.length];
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayFlattenDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayFlattenDescriptor.java
index 2b4e210..72d6c3d 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayFlattenDescriptor.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayFlattenDescriptor.java
@@ -141,7 +141,7 @@
             depthEval = args[1].createScalarEvaluator(ctx);
             list = new VoidPointable();
             pointable = new VoidPointable();
-            caster = new CastTypeEvaluator();
+            caster = new CastTypeEvaluator(null);
             depthArg = new TaggedValuePointable();
             orderedListBuilder = null;
             unorderedListBuilder = null;
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayIntersectDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayIntersectDescriptor.java
index ac192ef..c33222d 100755
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayIntersectDescriptor.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayIntersectDescriptor.java
@@ -194,7 +194,7 @@
             hashes = new Int2ObjectOpenHashMap<>();
             finalResult = new ArrayBackedValueStorage();
             listAccessor = new ListAccessor();
-            caster = new CastTypeEvaluator();
+            caster = new CastTypeEvaluator(null);
             // for functions that accept multiple lists arguments, they will be casted to open, hence item is ANY
             comp = BinaryComparatorFactoryProvider.INSTANCE
                     .getBinaryComparatorFactory(BuiltinType.ANY, BuiltinType.ANY, true).createBinaryComparator();
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayReplaceEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayReplaceEvaluator.java
index 329fa78..aeda168 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayReplaceEvaluator.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayReplaceEvaluator.java
@@ -108,7 +108,7 @@
         tempVal = new VoidPointable();
         item = new VoidPointable();
         listAccessor = new ListAccessor();
-        caster = new CastTypeEvaluator();
+        caster = new CastTypeEvaluator(null);
         orderedListBuilder = null;
         unorderedListBuilder = null;
 
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayStarDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayStarDescriptor.java
index f6d8d12..78d8d36 100755
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayStarDescriptor.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayStarDescriptor.java
@@ -198,7 +198,7 @@
             list = new VoidPointable();
             tempList = new VoidPointable();
             listEval = args[0].createScalarEvaluator(ctx);
-            caster = new CastTypeEvaluator();
+            caster = new CastTypeEvaluator(null);
             listAccessor = new ListAccessor();
             recordBuilder = new RecordBuilder();
             listBuilder = new OrderedListBuilder();
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeEvaluator.java
index 210149c..eb5275a 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeEvaluator.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeEvaluator.java
@@ -23,10 +23,10 @@
 import org.apache.asterix.om.pointables.base.DefaultOpenFieldType;
 import org.apache.asterix.om.pointables.base.IVisitablePointable;
 import org.apache.asterix.om.pointables.cast.ACastVisitor;
+import org.apache.asterix.om.pointables.cast.CastResult;
 import org.apache.asterix.om.types.ATypeTag;
 import org.apache.asterix.om.types.BuiltinType;
 import org.apache.asterix.om.types.IAType;
-import org.apache.hyracks.algebricks.common.utils.Triple;
 import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.api.exceptions.SourceLocation;
@@ -41,24 +41,14 @@
     private final IPointable argPointable = new VoidPointable();
     private final PointableAllocator allocator = new PointableAllocator();
     private IVisitablePointable inputPointable;
-    private IVisitablePointable resultPointable;
     private final ACastVisitor castVisitor = createCastVisitor();
-    private final Triple<IVisitablePointable, IAType, Boolean> arg = new Triple<>(null, null, null);
-
-    public CastTypeEvaluator() {
-        this(null);
-        // reset() should be called after using this constructor before calling any method
-    }
+    private final CastResult castResult = new CastResult(new VoidPointable(), null);
 
     public CastTypeEvaluator(SourceLocation sourceLoc) {
         this.sourceLoc = sourceLoc;
         // reset() should be called after using this constructor before calling any method
     }
 
-    public CastTypeEvaluator(IAType reqType, IAType inputType, IScalarEvaluator argEvaluator) {
-        this(reqType, inputType, argEvaluator, null);
-    }
-
     public CastTypeEvaluator(IAType reqType, IAType inputType, IScalarEvaluator argEvaluator,
             SourceLocation sourceLoc) {
         this.sourceLoc = sourceLoc;
@@ -68,10 +58,7 @@
     public void resetAndAllocate(IAType reqType, IAType inputType, IScalarEvaluator argEvaluator) {
         this.argEvaluator = argEvaluator;
         this.inputPointable = allocatePointable(inputType, reqType);
-        this.resultPointable = allocatePointable(reqType, inputType);
-        this.arg.first = resultPointable;
-        this.arg.second = reqType;
-        this.arg.third = Boolean.FALSE;
+        this.castResult.setOutType(reqType);
     }
 
     protected ACastVisitor createCastVisitor() {
@@ -86,19 +73,18 @@
             return;
         }
 
-        inputPointable.set(argPointable);
-        cast(result);
+        cast(argPointable, result);
     }
 
-    protected void cast(IPointable result) throws HyracksDataException {
-        inputPointable.accept(castVisitor, arg);
-        result.set(resultPointable);
-    }
-
-    // TODO: refactor in a better way
+    // TODO(ali): refactor in a better way
     protected void cast(IPointable argPointable, IPointable result) throws HyracksDataException {
         inputPointable.set(argPointable);
-        cast(result);
+        castInto(result);
+    }
+
+    protected void castInto(IPointable result) throws HyracksDataException {
+        inputPointable.accept(castVisitor, castResult);
+        result.set(castResult.getOutPointable());
     }
 
     // Allocates the result pointable.
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeLaxEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeLaxEvaluator.java
index be74580..56035a5 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeLaxEvaluator.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeLaxEvaluator.java
@@ -46,9 +46,9 @@
     }
 
     @Override
-    protected void cast(IPointable result) {
+    protected void castInto(IPointable result) {
         try {
-            super.cast(result);
+            super.castInto(result);
         } catch (HyracksDataException e) {
             if (LOGGER.isTraceEnabled()) {
                 LOGGER.log(Level.TRACE, e.toString(), e);
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ToObjectVarStrDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ToObjectVarStrDescriptor.java
index 6b72fc9..f9cf5a0 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ToObjectVarStrDescriptor.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ToObjectVarStrDescriptor.java
@@ -29,15 +29,14 @@
 import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
 import org.apache.asterix.om.functions.IFunctionTypeInferer;
 import org.apache.asterix.om.pointables.ARecordVisitablePointable;
-import org.apache.asterix.om.pointables.base.IVisitablePointable;
 import org.apache.asterix.om.pointables.cast.ACastVisitor;
+import org.apache.asterix.om.pointables.cast.CastResult;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.om.types.ATypeTag;
 import org.apache.asterix.om.types.IAType;
 import org.apache.asterix.om.types.TypeHelper;
 import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
 import org.apache.asterix.runtime.functions.FunctionTypeInferers;
-import org.apache.hyracks.algebricks.common.utils.Triple;
 import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
 import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
 import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
@@ -95,7 +94,7 @@
                 private final ARecordVisitablePointable argRec;
                 private final boolean castRequired;
                 private ACastVisitor castVisitor;
-                private Triple<IVisitablePointable, IAType, Boolean> castVisitorArg;
+                private CastResult castResult;
                 private boolean wroteEmpty;
 
                 private ToObjectVarStrEvaluator(final IEvaluatorContext ctx) throws HyracksDataException {
@@ -103,9 +102,8 @@
                     if (!TypeHelper.isFullyOpen(argType) && TypeHelper.isFullyOpen(outType)) {
                         castRequired = true;
                         argRec = new ARecordVisitablePointable(argType);
-                        ARecordVisitablePointable openRec = new ARecordVisitablePointable(NESTED_OPEN_RECORD_TYPE);
                         castVisitor = new ACastVisitor();
-                        castVisitorArg = new Triple<>(openRec, openRec.getInputRecordType(), Boolean.FALSE);
+                        castResult = new CastResult(new VoidPointable(), NESTED_OPEN_RECORD_TYPE);
                     } else {
                         castRequired = false;
                         argRec = null;
@@ -119,8 +117,8 @@
                     if (arg0.getByteArray()[arg0.getStartOffset()] == ATypeTag.SERIALIZED_RECORD_TYPE_TAG) {
                         if (castRequired) {
                             argRec.set(arg0);
-                            argRec.accept(castVisitor, castVisitorArg);
-                            resultPointable.set(castVisitorArg.first);
+                            argRec.accept(castVisitor, castResult);
+                            resultPointable.set(castResult.getOutPointable());
                         } else {
                             resultPointable.set(arg0);
                         }
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/AbstractRecordPairsEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/AbstractRecordPairsEvaluator.java
index e324230..974d621 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/AbstractRecordPairsEvaluator.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/AbstractRecordPairsEvaluator.java
@@ -43,7 +43,7 @@
     AbstractRecordPairsEvaluator(IScalarEvaluator eval0, IAType inputType) {
         this.eval0 = eval0;
         if (inputType != null) {
-            inputCaster = new CastTypeEvaluator(BuiltinType.ANY, inputType, eval0);
+            inputCaster = new CastTypeEvaluator(BuiltinType.ANY, inputType, eval0, null);
         }
     }
 
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordConcatEvalFactory.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordConcatEvalFactory.java
index 890bb13..68e089b 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordConcatEvalFactory.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordConcatEvalFactory.java
@@ -31,13 +31,13 @@
 import org.apache.asterix.om.pointables.base.DefaultOpenFieldType;
 import org.apache.asterix.om.pointables.base.IVisitablePointable;
 import org.apache.asterix.om.pointables.cast.ACastVisitor;
+import org.apache.asterix.om.pointables.cast.CastResult;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.om.types.ATypeTag;
 import org.apache.asterix.om.types.IAType;
 import org.apache.asterix.runtime.evaluators.common.ListAccessor;
 import org.apache.asterix.runtime.evaluators.functions.BinaryHashMap;
 import org.apache.asterix.runtime.exceptions.TypeMismatchException;
-import org.apache.hyracks.algebricks.common.utils.Triple;
 import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
 import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
 import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
@@ -100,11 +100,11 @@
         private final IScalarEvaluator[] argEvals;
         private IPointable[] argPointables;
         private ARecordVisitablePointable[] argRecordPointables;
-        private final ARecordVisitablePointable openRecordPointable;
+        private final ARecordVisitablePointable openRecord;
 
         private final BitSet castRequired;
         private ACastVisitor castVisitor;
-        private Triple<IVisitablePointable, IAType, Boolean> castVisitorArg;
+        private CastResult castResult;
 
         private final RecordBuilder outRecordBuilder;
         private final ArrayBackedValueStorage resultStorage;
@@ -123,12 +123,12 @@
             this.warningCollector = warningCollector;
 
             firstArg = new VoidPointable();
-            openRecordPointable = new ARecordVisitablePointable(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE);
+            openRecord = new ARecordVisitablePointable(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE);
 
             resultStorage = new ArrayBackedValueStorage();
             resultOutput = resultStorage.getDataOutput();
             outRecordBuilder = new RecordBuilder();
-            outRecordBuilder.reset(openRecordPointable.getInputRecordType());
+            outRecordBuilder.reset(openRecord.getInputRecordType());
 
             fieldMap = new BinaryHashMap(TABLE_SIZE, TABLE_FRAME_SIZE, outRecordBuilder.getFieldNameHashFunction(),
                     outRecordBuilder.getFieldNameHashFunction(), outRecordBuilder.getFieldNameComparator());
@@ -166,8 +166,7 @@
         private void initCastVisitor() {
             if (castVisitor == null) {
                 castVisitor = new ACastVisitor();
-                castVisitorArg =
-                        new Triple<>(openRecordPointable, openRecordPointable.getInputRecordType(), Boolean.FALSE);
+                castResult = new CastResult(openRecord, openRecord.getInputRecordType());
             }
         }
 
@@ -300,14 +299,14 @@
             if (argVisitablePointable != null) {
                 argVisitablePointable.set(recordPtr);
                 if (argCastRequired) {
-                    argVisitablePointable.accept(castVisitor, castVisitorArg);
-                    recordPointable = openRecordPointable;
+                    argVisitablePointable.accept(castVisitor, castResult);
+                    recordPointable = openRecord;
                 } else {
                     recordPointable = argVisitablePointable;
                 }
             } else {
-                openRecordPointable.set(recordPtr);
-                recordPointable = openRecordPointable;
+                openRecord.set(recordPtr);
+                recordPointable = openRecord;
             }
 
             List<IVisitablePointable> fieldNames = recordPointable.getFieldNames();
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordReplaceEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordReplaceEvaluator.java
index 550a84e..b2b8500 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordReplaceEvaluator.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordReplaceEvaluator.java
@@ -62,8 +62,8 @@
         this.eval1 = eval1;
         this.eval2 = eval2;
         openRecordPointable = new ARecordVisitablePointable(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE);
-        inputRecordCaster = new CastTypeEvaluator(BuiltinType.ANY, argTypes[0], eval0);
-        newValueRecordCaster = new CastTypeEvaluator(BuiltinType.ANY, argTypes[2], eval2);
+        inputRecordCaster = new CastTypeEvaluator(BuiltinType.ANY, argTypes[0], eval0, null);
+        newValueRecordCaster = new CastTypeEvaluator(BuiltinType.ANY, argTypes[2], eval2, null);
         // comp compares a value existing in the input record with the provided value. the input record is casted open
         comp = BinaryComparatorFactoryProvider.INSTANCE.getBinaryComparatorFactory(BuiltinType.ANY, argTypes[1], true)
                 .createBinaryComparator();
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordUnwrapEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordUnwrapEvaluator.java
index 522aa54..329f5b2 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordUnwrapEvaluator.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordUnwrapEvaluator.java
@@ -27,11 +27,11 @@
 import org.apache.asterix.om.pointables.base.DefaultOpenFieldType;
 import org.apache.asterix.om.pointables.base.IVisitablePointable;
 import org.apache.asterix.om.pointables.cast.ACastVisitor;
+import org.apache.asterix.om.pointables.cast.CastResult;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.om.types.ATypeTag;
 import org.apache.asterix.om.types.IAType;
 import org.apache.asterix.runtime.evaluators.functions.PointableHelper;
-import org.apache.hyracks.algebricks.common.utils.Triple;
 import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.data.std.api.IPointable;
@@ -44,23 +44,22 @@
     private final IPointable inputRecordPointable = new VoidPointable();
     private final IScalarEvaluator eval0;
     private ARecordVisitablePointable inputRecordVisitable;
-    private ARecordVisitablePointable openRecordVisitablePointable;
+    private final ARecordVisitablePointable openRecord;
     private boolean requiresCast = false;
     private ACastVisitor castVisitor;
-    private Triple<IVisitablePointable, IAType, Boolean> castVisitorArg;
+    private CastResult castResult;
     private final ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage();
     private final DataOutput resultOutput = resultStorage.getDataOutput();
 
     RecordUnwrapEvaluator(IScalarEvaluator eval0, ARecordType recordType) {
         this.eval0 = eval0;
-        openRecordVisitablePointable = new ARecordVisitablePointable(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE);
+        openRecord = new ARecordVisitablePointable(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE);
         if (recordType != null) {
             inputRecordVisitable = new ARecordVisitablePointable(recordType);
             if (hasDerivedType(recordType.getFieldTypes())) {
                 requiresCast = true;
                 castVisitor = new ACastVisitor();
-                castVisitorArg = new Triple<>(openRecordVisitablePointable,
-                        openRecordVisitablePointable.getInputRecordType(), Boolean.FALSE);
+                castResult = new CastResult(openRecord, openRecord.getInputRecordType());
             }
         }
     }
@@ -109,8 +108,8 @@
     }
 
     private ARecordVisitablePointable castToOpenRecord() throws HyracksDataException {
-        inputRecordVisitable.accept(castVisitor, castVisitorArg);
-        return openRecordVisitablePointable;
+        inputRecordVisitable.accept(castVisitor, castResult);
+        return openRecord;
     }
 
     private void writeValue(IVisitablePointable value) throws HyracksDataException {
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordValuesEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordValuesEvaluator.java
index 106a899..5e179f6 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordValuesEvaluator.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordValuesEvaluator.java
@@ -60,7 +60,7 @@
         if (recordType != null) {
             inputRecordOpen = recordType.isOpen() && recordType.getFieldTypes().length == 0;
             openRecordPointable = new ARecordVisitablePointable(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE);
-            inputRecordCaster = new CastTypeEvaluator(BuiltinType.ANY, recordType, eval0);
+            inputRecordCaster = new CastTypeEvaluator(BuiltinType.ANY, recordType, eval0, null);
             listBuilder = new OrderedListBuilder();
         } else {
             inputRecordOpen = true;