Let us dance: Understanding Classes through Musical Metaphor

Posted on September 25, 2015

This week, the Chicago Symphony Orchestra – at the beginning of its 2015-2016 season – performs Bolero (1928) by Maurice Ravel. Bolero is pure excitement. The piece consists of a single melody – a breathless, sensual, dance tune, performed by soloists, who showcase the coloristic effects of their instruments (e.g., flute, Bb and Eb clarinet, bassoon, oboe, trumpet – indeed, even the saxophone). With each instance of the melody, the piece grows in intensity, until its explosive, somewhat disorderly finale.

...show more...

Ravel's dance tune provides a meaningful analog to Ruby classes. A class is a "blueprint" or model for an idea. The Bolero melody can be understood as such a blueprint; each solo performance of it occurs as an "instance" of this blueprint. The solos vary, in terms of instrument (flute? oboe? saxophone?) and volume (let's say, on a scale of 1 to 10, with ten being the loudest). The Ruby class holds these attributes in instance variables – distinctly preceded with an "@." However, instance variables cannot appear outside of the class itself without a method that uses the variable. In other words, a separate, stand alone method gives power to an instance variable, as in this example:

class Bolero

    def initialize(instrument, volume)
        @instrument = instrument
      if volume <= 10 && volume >= 0
        @volume = volume
      else
        raise ArgumentError
      end
    end

    def instrument
      p @instrument
    end

    def volume
      p @volume
    end

end
solo_1 = Bolero.new("flute", 2)

solo_1.instrument
  => "flute"

solo_1.volume
  => 2

Making such methods can be tiresome, however. Ruby fortunately has "reader" and "writer" methods, which allow instance variables to live outside the class, but without the hassle of generating a unique method for each variable. The attr_reader method returns the variable without changing it; the attr_writer method deems the variable mutable, allowing it to be changed, though not read. Further, the attr_accessor method makes variables both "readable" and "writable."

class Bolero
    attr_accessor(:instrument, :volume)

    def initialize(instrument, volume)
        @instrument = instrument
      if volume <= 10 && volume >= 0
        @volume = volume
      else
        raise ArgumentError
      end
    end

end

Classes can encapsulate many more instance variables, sometimes very sophisticated ones that behave in weird and complex ways. With greater complexity comes greater frustration, thrills, and possibilities, offering us a reason to dance.

...show less...

Nutritious Innumerable Universe

Posted on September 19, 2015

My last post explored the differences and similarities between two types of containers: arrays (lists of objects ordered numerically) and hashes (lists of objects organized into key-value pairs). Hashes and arrays bring order to our disorganized, complex, troubling, exhilarating, confusing, beautiful universe. Nonetheless, the full organizational potential of hashes and arrays exists not in the containers themselves, but in the myriad ways we can access and manipulate them.

...show more...

Behold. The innumerable. The innumerable, or innumerable module, bestows objects with great power. It allows objects to access bundles of capable methods. These methods depend upon the notion of .each, which iterates over collections by pushing each element into a code block, as in this example that helps to describe the items in my fridge after shopping at the Division Street Farmers' Market:

array = ["green beans", "apple", "pepper", "watermelon"]
array.each {|x| p "yummy " + x }
          => yummy green beans
             yummy apple
             yummy pepper
             yummy watermelon

Innumerable methods offer more subtle, often more powerful variants of the .each method, for instance: .each_with_index. The .each_with_index method considers each element of an array as well as its index number, as in this example:

array = ["green beans", "apple", "pepper", "watermelon"]
array.index_with_each {|x, index| p "yummy #{x} @ #{index}" }
          => "yummy green beans @ 0"
             "yummy apple @ 1"
             "yummy pepper @ 2"
             "yummy watermelon @ 4"

The .each_with_index method, perhaps most compellingly, can help transform an array into a hash, in which the elements of the array appear as the hash keys and the index numbers appear as the hash values:

hash = {}
array = ["green beans", "apple", "pepper", "watermelon"]
array.each_with_index {|x, index| hash[x] = index }
          => { "green beans" => 0,  "apple" => 1, "pepper" => 2, "watermelon" => 3}

The .each_with_index method and its cousin innumerables can help create sophisticated programs – programs that can sort vegetables or organize the universe.

...show less...

Containers, Collections, Chicago

Posted on September 13, 2015

I recently moved into a studio apartment in the heart of Chicago (Near North Side). I can walk to Oak Street Beach, Navy Pier, and on particularly nice days, Millennium Park. Though a portal into the beauty of Chicagoland, my apartment – due to it spacial limitations – demands an exhaustive system of organization. I thus use various containers (boxes, Tupperware, shelving units, etc.) to establish order. Some of these storage containers place my belongings into a precise, linear order: the top drawer of my (modest) dresser holds underwear, the second drawer – bras, the third – socks and running shorts, and the bottom – leggings. I also have a refrigerator, which contains structure, but not precise, numerical order: when I buy a new food item, I put it in the fridge, where it resides until I eat it or replace it with something else.

...show more...

Arrays and hashes work similarly. They are containers (or lists) for objects. The objects in an array appear between brackets, like so:

dresser_drawers = ["underwear", "bras", "socks and shorts", "leggings"]

An array organizes its contents in numerical order, starting at zero. In the "dresser_drawers" array, "underwear" sits in the zeroth position, "bras" sit in the first position, and so on. Hashes are also containers that organize lists of objects. Hashes, however, present a slightly more sophisticated if less linear system of order. The objects in a hash appear between two curly brackets, and each object contains two parts – a key and its value, like so:

refrigerator = { "cheese_drawer" => "Parmesan",
        "vegetable_crisper" => "corn",
        "bottom_shelf" => "milk",
        "door" => "butter" }

The hash array collects each object, not according to a numerical index, but rather according to the objects themselves. Therefore, to access an object in the array, I simply call the object by its name, not by it integer position. Like the containers in my studio apartment, arrays and hashes serve different, but equally useful purposes – helping to bring order and structure to the world around us.

...show less...

The World Wide Web According to Bach

Posted on September 4, 2015

The first movement of Bradenburg Concerto No. 1 by JS Bach (1685-1750) contains a handful of musical ideas: an oscillating melody in the violins and oboes superimposed over a disruptive "hunting" horn call. The fourth movement of Symphony No. 82 by Josef Haydn (1732-1809) presents one prominent melody, a playful pastoral dance, that recurs in every section and subsection of the movement. String Quartet, Op. 28 by Anton Webern (1883-1945) contains a four-note cell – a reference to Bach's name – that repeats and repeats, providing the basic musical material for the entire piece.

...show more...

Written by composers from three very different historical moments, these works present examples of, what some thinkers call, "motivic economy," a principle of music composition that celebrates efficient repetition. This principle, in one sense, suggests that repetition creates coherency, intelligibility, and beauty. Repetition, in other words, makes masterworks masterful.

To write good CSS requires some understanding of Bach, Haydn, and Webern – or, at least, an understanding of motivic economy. HTML gives the website its basic content, and CSS shapes, colors, and brings to life the elements of HTML. CSS and HTML files thus communicate together. An HTML file contains elements...and elements within elements...and elements within elements within elements. An element can indicate a header, a paragraph, a blockquote, and about one hundred other "semantic" things. The CSS file selects these elements and adds style to them.

In HTML, "class" labels can appear next to elements, e.g., p class="ex-l". The class – a type of CSS selector – prepares the element for styling in CSS: the class can receive several style values, which are then applied to the element itself in the HTML. Several elements can share a class. For instance, all link elements (the "a" tag) and headers (the "h" tags) might share a class of "strong." In the CSS, the "strong" class could receive, let's say, a font-weight of bold: all links and headers on the site would in turn be bolded.

"ID" labels can also appear next to elements, e.g., p id="p-xs". However, IDs do not function as classes do. An ID is unique; it can only select one element, one time. IDs can be useful, if the site has an element with very specific styling needs (perhaps, a detail in the footer or an aside). Still, an HTML file with an excess of IDs likely has some problems: mainly, the code lacks "motivic economy." A plethora of IDs results in verbose, bombastic, ineloquent CSS files. Whereas, a collection of cleverly organized classes creates intelligible, precise CSS, the kind of CSS that Bach, Haydn, or Webern might write.

...show less...