loading...

Using ANT to grok OOP

jaybeekeeper profile image Jarret Bryan ・6 min read

OOO & OOP

One of the first things that came to mind when I read that Ruby was an Object Oriented Programming language was Object Oriented Ontology. The first draft of this blog post was a desperate attempt to link Ruby's conception of the Object to Bruno Latour's Actor Network Theory - I got Reassembling the Social off of my bookshelf; I thumbed through as much of the text as I could, trying to dig into the particulars of intermediaries and mediators, not privileging human actors over objects, relearning what the five uncertainties are --

It was largely a trainwreck, not least because ANT is famously obtuse and difficult to summarize and I really didn't have the time to relearn the particulars of Latour's conception of ontology; so here I want less to draw direct parallels and risk butchering and misunderstanding Bruno Latour's ontological claims and focus more on how the ideas (or maybe the idea of the ideas) allowed me to grok what Ruby's Object Oriented paradigm means for understanding objects and the relations between them through other objects.

Everything is an Object

So a concept that I've come across numerous times in my early experiences with Ruby is the idea that everything in Ruby is an object. Depending on who you talk to, there seem to be very minor exceptions (are methods objects? are blocks objects? both can be wrapped in objects?), but they seem to be exceptions that prove the rule more so than undermine it.

Every singular object is an instance of a Class. Even the object of Class is in instance of the class Class. And by virtue of being a specific kind of class, an object has attributes particular to that class that can be called upon.

#even nil has a class!
nil.class
 => NilClass 

Object Relations

Therefore, in an object oriented language like Ruby, understanding the relationships among objects is very important - and there is no privileging one object over another. And relationships among objects must be understood through other objects. It's a level playing field. And so what we might consider objects without agency or conceptions of ownership, suddenly have ownership in relation to other objects. Here's where I wanted to draw parallel's to Latour's conception of the actant:

To break away from the influence of what could be called 'figurative sociology,' ANT uses the technical word actant that comes from the study of literature. Here are four ways to figure out the same actant: 'Imperialism strives for unilateralism'; 'The United States wishes to withdraw from the UN'; 'Bush Junior wishes to withdraw from the UN':; 'Many officers from the Army and two dozen neo-con leaders want to withdraw from the UN.' That the first is a structure trait, the second a corporate body, the third an individual, the fourth a loose aggregate of individuals makes a big difference of course to the account, but they all provide different figurations of the same actions. None of the four is more or less 'realist', concrete', 'abstract' or 'artificial' than the others.

Latour, Bruno, Reassembling the Social Oxford University Press, 2009, 54

For our purposes, an actant is just anything that enables action or can be the fulcrum of an action.

This points to an idea of 'generalised symmetry', in which there is no 'a priori asymmetry' among actors (commonly 'subjects) with intentional action and a material world of causal relations. We use the same analytical framework for all actors, whether they are a person, or a computer, or an idea about technology. This can get esoteric fairly esoteric fairly quickly, so let's drill down to how I understood the parallel in Ruby.

For example, if I make a class "Elevator" with a attribute "name", and "is_functioning" as a boolean that defaults to "true" then I can be sure that anything initialized with that class will have those attributes.

class Elevator

    attr_reader :name
    attr_accessor :is_functioning

    def initialize(name)
        @name = name
        @is_functioning = true
    end
end

elevator_9 = Elevator.new("Elevator No. 9")
#<Elevator:0x00007ff5ce3bc998 @functioning=true, @name="Elevator No. 9">

elevator.name
# "Elevator No. 9" 

elevator.is_functioning
#true

I can also make a class "Inspector" with its own set of attributes

class Inspector
    attr_reader :name

    def initialize(name, philosophy)
        @name = name
        @philosophy = philosophy
    end
end

lila_mae = Inspector.new("Lila Mae Watson", "Intuitionism")
#<Inspector:0x00007fccd6a0fdc0 @name="Lila Mae Watson", @philosophy="Intuitionism">

So I have a class Elevators, and a class Inspectors. There is nothing inherent to the code that implies a direct relationship. But the object oriented paradigm is useful to mapping to real world relationships; the thorn here being that in the real world, an Inspector is a person with agency and can claim ownership over something, while an elevator cannot. But with Ruby, there is no such a priori asymmetry. Both are objects (and both are actors) - so we use the same framework to understand them. And as a result we can say, an Inspector "has many" (or inspects many) elevators. And an Elevator "has many" (or is inspected by many) inspectors.

More importantly, we can understand the relationship between the two as an object as well. These two actors (the Ruby objects of the class Elevator and Inspector) form a temporary network, which becomes an assemblage of relations - Latour's "actant." And the point of interaction, the "Elevator Inspection," can be represented as a Ruby Object as well. Picture the below:


class ElevatorInspection

    def initialize(elevator, inspector)
            @elevator = elevator
            @inspector = inspector
    end

end

Here we see that every instance of the class ElevatorInspection is initiated with instances of the classes Elevator and Inspector. If within the class we define a class method .all to collect every instance -


class ElevatorInspection

    @@all = []

    def self.all
        @@all
    end

    def initialize(elevator, inspector)
            @elevator = elevator
            @inspector = inspector
            self.class.all << self
    end

end
  • then we can in theory understand the entirety of the relationship between the class Elevators and Inspectors, since every instance of ElevatorInspection class will contain information from the other two. So we understand that Elevators "have many" Inspectors through the ElevatorInspection class - and vice versa. This object can act as our "Single Source of Truth" and I argue parallel's the 'actant,' modifying the actors of Elevator and Inspector by allowing a relationship of 'ownership.' Our entire assemblage can be represented as an object, and, like an actant holds a relevance only particular to this relationship.

Is it coding as ontology?

If I've lost you, or the parallel's seem tenuous, I don't blame you: but the key takeaway for me in drawing these parallels is simply that Ruby's object oriented paradigm allows us to model real world relationships - and these relationships can be understood in terms of objects as well since we do not need to adjust our analytical framework. And since we can assign attributes to any given object in Ruby, by simply identifying the object that can be considered representative in the relationship, we can modify and manipulate that object to understand the entirety of the relationship. We've abstracted the relationship as a Ruby object.

So let's finally drill down to what this looks like in Ruby:

class Elevator  
    attr_reader :name
    attr_accessor :is_functioning

    def initialize(name)
        @name = name
        @is_functioning = true
    end
end

class Inspector
    attr_reader :name

    def initialize(name, philosophy)
        @name = name
        @philosophy = philosophy
    end
end

class ElevatorInspection
    @@all = []

    def self.all
        @@all
    end

    def initialize(elevator, inspector)
        @elevator = elevator
        @inspector = inspector
        self.class.all << self
    end
end

elevator_9 = Elevator.new("Elevator No. 9")
=> #<Elevator:0x00007fab56b99c00 @is_functioning=true, @name="Elevator No. 9">

lila_mae = Inspector.new("Lila Mae Watson", "Intuitionism")
=> #<Inspector:0x00007fab55c6c070 @name="Lila Mae Watson", @philosophy="Intuitionism">

 ElevatorInspection.new(elevator_9, lila_mae)
=> #<ElevatorInspection:0x00007fab56087a10
 @elevator=#<Elevator:0x00007fab56b99c00 @is_functioning=true, @name="Elevator No. 9">,
 @inspector=#<Inspector:0x00007fab55c6c070 @name="Lila Mae Watson", @philosophy="Intuitionism">>


Since every instance of the ElevatorInspection class "belongs to" an Elevator and an Inspector, I can find out everything I need about the relationships between the two classes, through the ElevatorInspection Class - you'll notice the ElevatorInspection instance that I've initiated has all the information about both relevant Elevator and Inspector instances. The key is identifying the object that is representative of and maintains the relationship.

Further Reading & Sources

Ruby, and Seeing Everything as an Object

Bruno Latour, Reassembling the Social - An Introduction to Actor Network Theory

Darryl Cressman - A Brief Overview of Actor-Network Theory: Punctualization, Heterogeneous Engineering & Translation

Actor Network Theory in Plain English

Science & Technology Studies Wikipedia Page

Posted on by:

jaybeekeeper profile

Jarret Bryan

@jaybeekeeper

web developer | technologist | #codenewbie | alum of @flatironschool

Discussion

markdown guide