On this page:
22.1 Treating things as objects
22.2 Long Live Lambda!
22.3 Method to the madness
22.4 Student Wish List
22.5 A concrete syntax for classes
22.6 A common refrain
22.7 Things to consider:
8.7

22 Overcharge: Objects, but it’ll cost you

image Source code.

    22.1 Treating things as objects

    22.2 Long Live Lambda!

    22.3 Method to the madness

    22.4 Student Wish List

    22.5 A concrete syntax for classes

    22.6 A common refrain

    22.7 Things to consider:

22.1 Treating things as objects

Many of the most popular programming languages use Objects as a way to organize code and provide opportunities for abstraction. One of the key ideas that objects provide is encapsulation: The idea that we can group data with the functionality for working on/with that data. The functionality that’s been packaged with the data is known as a method.

This set of lecture notes is not meant to be comprehensive, instead it is meant to give a high-level view of how you might implement objects, starting from a language like Loot.

22.2 Long Live Lambda!

One way to think about objects is that it’s a package of data along with code (the methods). This is just the other side of how we implement lambdas: closures which have data associated with code. We will explore this relationship later on.

22.3 Method to the madness

Methods are functions that have implicit access to a particular object’s data. Often we call the particular object this. Which means that however we implement objects, we have to make sure that this scoping is respected.

22.4 Student Wish List

In lecture, we discussed how we expect objects to behave, and what features we expect. This is the list of things we came up with:

One distinction we made was that between a class (the ’type’ of an object) and the object itself (the actual value that we construct/manipulate).

22.5 A concrete syntax for classes
(class (dog n w b)
  (name   (if (= b "yorkshire")
            (append "sir " n)
            n))
  (weight (to-metric w))
  (breed  (lower-case b))
  (bark (lambda () (breed-volume breed "bark!"))))

Above we are doing a few things:

Notice that we aren’t making a real distinction between fields and methods: methods are just function-valued fields!

22.6 A common refrain

You may remember this from our Loot notes:

So now:
  • Q: How can we represent functions?

  • A: With functions!?

  • Q: How can we represent methods?

  • A: With functions!?

  • Q: Wait, what?

It turns out that we can leverage the way that closures are implemented in the heap in order to implement objects. Given the example class above, we could translate it to the following function definition:

(racketblock (define (dog n w b) (let ((name (lambda () (if (= b "yorkshire") (append "sir " n) n)) (weight (lambda () (weight (to-metric w)))) (breed (lambda () (breed (lower-case b)))) (bark (lambda () (breed-volume breed "bark!"))))) (lambda (field . xs) (match field [’name (apply name xs)] [’weight (apply weight xs)] [’breed (apply breed xs)] [’bark (apply bark xs)])))) )

Let’s start from the end:

We’re creating a lambda that takes a symbol representing the field we want, and the rest of the arguments as a list. We dispatch on the field, deciding which field we want to access out of this lambda.

Each field has been converted into a lambda that captures the environment that it needs (from the constructor’s arguments). When we (apply name xs) we are calling the lambda that represents the field.

22.7 Things to consider: