Taro Logo

Check if Object Instance of Class

Medium
Google logo
Google
2 views

Write a function that checks if a given value is an instance of a given class or superclass. For this problem, an object is considered an instance of a given class if that object has access to that class's methods.

There are no constraints on the data types that can be passed to the function. For example, the value or the class could be undefined.

Example 1:

Input: func = () => checkIfInstanceOf(new Date(), Date)
Output: true
Explanation: The object returned by the Date constructor is, by definition, an instance of Date.

Example 2:

Input: func = () => { class Animal {}; class Dog extends Animal {}; return checkIfInstanceOf(new Dog(), Animal); }
Output: true
Explanation:
class Animal {};
class Dog extends Animal {};
checkIfInstanceOf(new Dog(), Animal); // true

Dog is a subclass of Animal. Therefore, a Dog object is an instance of both Dog and Animal.

Example 3:

Input: func = () => checkIfInstanceOf(Date, Date)
Output: false
Explanation: A date constructor cannot logically be an instance of itself.

Example 4:

Input: func = () => checkIfInstanceOf(5, Number)
Output: true
Explanation: 5 is a Number. Note that the "instanceof" keyword would return false. However, it is still considered an instance of Number because it accesses the Number methods. For example "toFixed()".

Solution


Clarifying Questions

When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:

  1. Can I assume the `object` parameter will always be an object instance, and the `class` parameter will always be a class type?
  2. If the object is an instance of a subclass of the provided class, should the function return `true`?
  3. Are we working with built-in classes, custom classes, or both? Are there any limitations on the types of classes to consider?
  4. Should I handle the case where either the object or the class is `null` or `undefined` (or equivalent in the relevant language)?
  5. Is there a specific error handling mechanism that is preferred (e.g., throw an exception, return a specific error value) if invalid inputs are provided?

Brute Force Solution

Approach

The brute force method involves exhaustively checking whether an object is an instance of a given class. We explore all possibilities by comparing the object's type against the class and its inheritance hierarchy. This ensures we leave no stone unturned in our verification process.

Here's how the algorithm would work step-by-step:

  1. First, directly check if the object is exactly of the specified class type.
  2. If the direct check fails, examine the class that the object actually belongs to and see if it's inheriting from the specified class.
  3. Continue this process by walking up the chain of inheritance from the object's class, checking each parent class to see if it matches the specified class.
  4. If at any point in this upward climb through parent classes you find a match, then the object is an instance of the specified class.
  5. If you reach the very top of the inheritance chain (the most fundamental class) and haven't found a match, then the object is not an instance of the specified class.

Code Implementation

def is_object_instance_of_class(object_to_check, class_to_check):
    # Directly check if the object is of the specified class.
    if type(object_to_check) is class_to_check:
        return True

    object_class = type(object_to_check)

    # Iterate through the base classes to check inheritance.
    for base_class in object_class.__bases__:

        # Recursively check parent classes for the specified class
        if base_class is class_to_check:
            return True

        # Check the base class's inheritance
        if is_object_instance_of_class(base_class, class_to_check):
            return True

    # If none of the base classes match, return False.
    return False

Big(O) Analysis

Time Complexity
O(h)The primary operation is traversing the inheritance hierarchy of the object to check if the object's class or any of its parent classes match the specified class. The time complexity is directly proportional to the height (h) of the inheritance tree. In the worst-case scenario, we might have to traverse the entire inheritance chain up to the base class to determine if there's a match. Therefore, the time complexity is O(h), where h represents the height of the object's class inheritance tree.
Space Complexity
O(1)The described approach iterates through the inheritance hierarchy of the object's class. The algorithm's space complexity is determined by the number of temporary variables used during the inheritance traversal, such as variables to hold the current class being examined. These variables occupy a constant amount of space, irrespective of the depth of the inheritance tree, which is represented by N. Therefore, the space complexity remains constant, resulting in O(1).

Optimal Solution

Approach

To determine if something belongs to a specific type, we avoid complicated checks. The most efficient way is to ask directly if the thing 'is' the type we're interested in, using the language's built-in tool for this purpose. This avoids manual comparisons or guesswork.

Here's how the algorithm would work step-by-step:

  1. Take the thing you want to check and the type you suspect it might be.
  2. Use the special 'is' tool provided by the programming language to directly ask if the thing is an example of that type.
  3. The 'is' tool will give you a simple 'yes' or 'no' answer.

Code Implementation

def is_object_instance_of_class(object_to_check, class_to_check):
    # Check if the object is an instance of the given class.

    if isinstance(object_to_check, class_to_check):
        # The object is an instance of the class.
        is_instance = True

    else:
        # The object is not an instance of the class.
        is_instance = False

    # Return whether the object is an instance of the class.
    return is_instance

def is_object_instance_of_class_alt(object_to_check, class_to_check):
    # Directly using 'isinstance' is the most pythonic approach.
    return isinstance(object_to_check, class_to_check)

Big(O) Analysis

Time Complexity
O(1)The 'is' operator in most languages performs a type check directly. It does not iterate through any data structures or perform comparisons proportional to input size. Therefore, the time complexity of directly checking if an object is an instance of a class using the 'is' operator is constant, or O(1).
Space Complexity
O(1)The provided explanation describes directly checking if an object is an instance of a class. This operation typically involves no auxiliary data structures or memory allocation that scales with the input size. The 'is' operation is a built-in language feature that performs the type checking in place without needing extra space. Therefore, the space complexity remains constant regardless of the input object or class being checked.

Edge Cases

CaseHow to Handle
Null or undefined objectReturn false immediately if the object is null or undefined to avoid errors.
Null or undefined classReturn false immediately if the class is null or undefined to prevent issues.
Object is created from a different context (e.g., different iframe)Check the object's constructor and prototype chain carefully, as cross-context instances can cause unexpected behavior.
Class is a primitive type (e.g., Number, String, Boolean)Return false; primitive types should not be considered classes in this context.
Inheritance chains – object is an instance of a superclassRecursively traverse the prototype chain of the object to check against all superclasses.
Object has a modified prototype chainEnsure that prototype checks are robust against prototype pollution attacks or intentional prototype modifications.
The class has a custom `[Symbol.hasInstance]` methodRespect the class's `[Symbol.hasInstance]` method if present, as it overrides the default behavior.
Class is an abstract class or interfaceDetermine if the intended behavior should treat instances of concrete subclasses as instances of the abstract class/interface.