@Override
        public boolean equals(final Object f, final Object s) {
            // numbers and collections with different hashcode can be equal
            if (f != null && s != null && f.hashCode() != s.hashCode()
                    && !(f instanceof Number) && !(f instanceof Collection) && !(f instanceof Map))
                return false;

            // shortcut a long, drawn out element by element comparison
            if (containersOfDifferentSize(f, s))
                return false;

            // For Compare, NaN always produces ERROR
            if (eitherAreNaN(f, s))
                return false;

            // For Compare we do not cross type boundaries, including null
            if (!comparable(f, s))
                return false;

            try {
                // comparable(f, s) assures that type(f) == type(s)
                final Type type = Type.type(f);
                return comparator(type).compare(f, s) == 0;
            } catch (GremlinTypeErrorException ex) {
                /**
                 * By routing through the compare(f, s) path we expose ourselves to type errors, which should be
                 * reduced to false for equality:
                 *
                 * compare(NaN, anything) -> ERROR -> FALSE for equality
                 * compare(Type1, Type2) -> ERROR -> FALSE for equality
                 *
                 * Can also happen for elements nested inside of collections.
                 */
                return false;
            }
        }
Test two Gremlin values for equality per the Comparability semantics. Returns false for NaN comparison
and for cross-type comparison (including nulltype).

Use this method for P.eq/neq.
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/GremlinValueComparator.java