ICS 32 Winter 2022
Exercise Set 8

Due date and time: Tuesday, March 8, 11:59pm


Getting started

First of all, be sure that you've read the Reinforcement Exercises page, which explains everything you'll need to know, generally, about how the reinforcement exercises will work this quarter. Make sure you read that page before you continue with this one.


Problem 1 (2 points)

We saw this week that Python allows us to write higher-order functions, which are functions that either take one or more functions as arguments, or return functions as their result, or both; in other words, they're functions that operate on other functions in some way.

If you were to sum up, in a couple of sentences, why we want higher-order functions in general, what would you say about it? There's no need to write multiple paragraphs here; the goal here is to succinctly talk in general about the benefits of the technique. Why do we care about it? (I mean, sure, you might care about it because it's part of the course and makes up part of your grade in the course, but that's obviously not what I'm asking here.)

What to submit

Submit one PDF file named problem1.pdf, which contains your answer to this question


Problem 2 (3 points)

Background

A few weeks ago, we learned about Python's peculiarly-named feature called Duck Typing, which essentially means that we can ask objects to do anything, as long as it's something they're capable of doing; specifically what happens is governed by the types of those objects, so the "right thing" happens automatically.

As a consequence, if you have many objects of different types that nonetheless share an interface — which is to say that there's at least one way in which the objects can be used interchangeably — then this allows us to write code that doesn't have to know ahead of time exactly what types of objects it will receive as input, yet the "right thing" will happen automatically when we use them, as long as all of the objects are capable of doing what our code asks them to do (i.e., only uses the interface). That conversation we had was accompanied by an example, in which we wrote classes that shared an interface that we called Calc, in which all of the classes had a one-argument method called calculate.

When shown that example, it's not uncommon for students to ask this question: Why couldn't we have just solved that problem with functions? The answer I usually give revolves around two things:

  1. Because we're learning a new technique, which we'll want to be able to recognize it when we see it and put into action when we need it, but in an example that's not so overly-complex that we miss the point of it.
  2. Because there are things that objects of classes can do that functions can't.

Now, to be fair, the second part of the answer is actually not entirely true. It's safer to say that, at that point, there were things that we knew objects of classes could do that we didn't know that functions could also do; the line distinguishing classes from functions is blurrier than you might have imagined. But, this week, we've expanded our understanding of what functions can do, so let's apply that expanded understanding to the Calc example from the Duck Typing notes.

What to do

In a Python script named problem2.py, re-implement the Calc example from the Duck Typing notes, meeting the following requirements, which are different than what I was aiming for in that example.

Additionally, in a Python script named problem2tests.py, write unit tests (using the unittest module from the Python standard library) for the individual calcs and for your newly-written run_calcs function.

You might want to use Test-Driven Development to do all of this work, as additional practice with that technique, though that's up to you. (Either way, you'll need to write tests, but you might find them a lot more valuable if you write them earlier rather than waiting until the end, when they may seem more like busywork.)

Docstrings are not necessary here, as we've already agreed on what problems we're solving. Type annotations are also not necessary here, mainly because there's so much flexibility in this example, they'd be difficult to write.

What to submit

Submit two Python scripts: One named problem2.py that contains your re-implementation of the Calc example and another named problem2tests.py that contains your unit tests for your re-implemented example.


Problem 3 (2 points)

One level of understanding how to write programs is to be able to copy techniques that you see other people using; a much more important level of understanding is to be able to choose those techniques yourself when they're appropriate. While experience is the best teacher of design concepts like this, the way to accelerate that learning process is to be sure that you understand why you're doing the things you're doing, so that your palette of choices grows more quickly.

Along those lines, let's consider a technique that we used in object-oriented Tkinter applications. When we wanted to "wire up" event handlers in these applications, we used a Python concept known as bound methods to do so. That's a new technique that we'd not seen previously, so it's worth pausing to make sure that we understand what purpose it served. To solidify your understanding, think about and then answer two questions about that technique.

  1. In an object-oriented Tkinter application (i.e., one in which we implemented the user interface as a class), why did we use bound methods when we set up our event handlers?
  2. Suppose that bound methods didn't exist in Python, so that we couldn't have solved the problem that way. Using only techniques that have been taught in this course to date, suggest another way that we could have set up our event handlers, assuming that our design otherwise wasn't going to change (i.e., we're still implementing our user interface as a class, with an object of that class representing a running instance of that user interface). Demonstrate your chosen technique with a short example. There's no need to write an entire program; show us enough code for us to understand the technique, but focus some effort on eliminating things that aren't necessary to convey your idea. (This is a really useful practical skill that you'll want to learn; being able to explain complex technical matters in simple language and with clearly-chosen examples is handy for software professionals, not just for teachers.)

What to submit

Submit one PDF file named problem3.pdf, which contains your answers to these two questions.


Problem 4 (3 points)

Tkinter is a library that we can use to implement programs that have graphical user interfaces (GUIs). While the norms of GUI styling change as the years go on, Tkinter's built-in widgets are still reasonably recognizable, in terms of what their goals are:

However, one problem you face when designing a program with a GUI is the problem of layout, which is to say that we need to decide where each of the widgets will be placed in the window. To make matters a little more complicated, we also need to decide how that placement will change as the window's size changes; we may want some widgets to grow and shrink, while others maintain a constant size. The grid layout in Tkinter is the main mechanism we saw for controlling the placement of widgets in a window, so let's make sure you've had a chance to practice with it, by implementing a layout.

Let's suppose you're building a simple chat application that allows users to talk to one another. Let's say that when you start up your program, it should look like this:

It's fine for yours to use a different font, but there needs to be a Listbox at the top of the window, an Entry widget next to a Button labeled Send below that, and a Quit button in the lower-right corner. There needs to be at least one row of text in the Listbox, but there is no specific requirement about how many there need to be or what they need to say. (Don't worry about making the list scrollable, but you're welcome to dig into figuring that out, if you'd like.)

After resizing the window to become larger, it should look (more or less) like this:

Note that the placement of the widgets have changed in the ways described below; your implementation should do likewise.

It is not necessary to implement any actual functionality here; the focus is entirely on the layout of the widgets. There doesn't need to be any effect when you click buttons, enter text, or select rows in the list, though you're welcome to do anything you'd like in those cases, as long as we don't need to set anything up to be able to run your program. (How we'll test your submission is to run the program, look at the layout of widgets in the window, then see how that layout changes as the size of the window changes. That's all we're interested in here, so that needs to work properly "out of the box.")

What to submit

Submit one Python script named problem4.py, which contains a Tkinter-based application that implements the layout specified.


Deliverables

In Canvas, you'll find a separate submission area for each problem. Submit your solution to each problem into the appropriate submission area. Be sure that you're submitting the correct file into the correct area (i.e., submitting your Problem 1 solution to the area for Problem 1, and so on). Under no circumstances will we offer credit for files submitted in the incorrect area.

Submit each file as-is, without putting it into a Zip file or arranging it in any other way. If we asked for a PDF, for example, all we want is a PDF; no more, no less. If you submit something other than what we asked for, we will not be offering you any credit on the submission. There are no exceptions to this rule.

Of course, you should also be aware that you're responsible for submitting precisely the version of your work that you want graded. We won't regrade an exercise simply because you submitted the wrong version accidentally, and we won't be able to offer any credit on exercises that you forgot to submit.

Can I submit after the deadline?

Unlike some of the projects in this course, the reinforcement exercises cannot be submitted after the deadline; there is no late policy for these. Each is worth only 3% of your grade, so it's not a disaster if you miss one of them along the way.