From 8a0f933b1aceeeee62c8600df1734efb919f1c98 Mon Sep 17 00:00:00 2001 From: Jeremy Douglass Date: Sat, 9 Sep 2017 13:26:40 -0700 Subject: [PATCH 01/12] tutorials: add objects tutorial --- tutorials/index.yml | 1 + tutorials/objects/.property.yml | 5 + tutorials/objects/imgs/objects.jpg | Bin 0 -> 40501 bytes tutorials/objects/index.md | 384 +++++++++++++++++++++++++++++ 4 files changed, 390 insertions(+) create mode 100644 tutorials/objects/.property.yml create mode 100644 tutorials/objects/imgs/objects.jpg create mode 100644 tutorials/objects/index.md diff --git a/tutorials/index.yml b/tutorials/index.yml index b9aba15..44941a4 100644 --- a/tutorials/index.yml +++ b/tutorials/index.yml @@ -1,3 +1,4 @@ index: - gettingstarted - drawing + - objects diff --git a/tutorials/objects/.property.yml b/tutorials/objects/.property.yml new file mode 100644 index 0000000..80ef27d --- /dev/null +++ b/tutorials/objects/.property.yml @@ -0,0 +1,5 @@ +image: objects.jpg +title: Objects in Processing.R +author: Shawn T. O'Neil +introduction: The basics of object-oriented programming. +level: Intermediate diff --git a/tutorials/objects/imgs/objects.jpg b/tutorials/objects/imgs/objects.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6aa85123f3d79bc788256f5691d57f27a1945f1e GIT binary patch literal 40501 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 z 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 RSxgto4KBr4d{>gj{u{9r{CfZZ literal 0 HcmV?d00001 diff --git a/tutorials/objects/index.md b/tutorials/objects/index.md new file mode 100644 index 0000000..ace6fcb --- /dev/null +++ b/tutorials/objects/index.md @@ -0,0 +1,384 @@ +### What's an object? + +The usual business of programming involves *data* (lists, vectors, matrices, etc.) and *functions*, which take data as input and *do something* (like draw a circle) or *return* something (maybe the result of a complex calculation). + +Frequently, the same pieces of data and function are used repeatedly as a group--to simulate a moving ball for example, we will have data on the ball's location (x and y), its speed (how many pixels it will move in the x and y direction in the next timestep), a radius, and maybe something like an ID string. A function like `move()` would take the position and speed data, and update the position. A function like `display()` needs position information and the radius to draw the ball. + +An **object** is a more formal way to group all of these pieces together. Objects are not strictly necessary for writing programs, but by organizing related data and functions they can simplify the process considerably. + +We'll often talk about **classes** as well--a class is the "blueprint" for potentially many objects of the same type. The objects themselves are the actual collections of data built from the class template. Let's consider our ball example, a `Ball` class is code that specifies that all `Ball` objects must have an `xloc`, `yloc`, `xspeed`, `yspeed`, `radius`, and `id`, as well as a function `display()` and a function `move()`. + +![enter image description here](https://imgur.com/JfzopbP.png) + +In a way, the word `Ball` itself is a bit of data associated with an object, since we need some way to know that an object `x` is a `Ball`, and not, say, a `Car`. + +Usually we'll use capital initials for class names (e.g. `Ball` rather than `ball`). However, R is not as consistent about this as some other languages, so don't be too surprised to see exceptions to this rule. Some special terminology is also used: functions that that are part of classes (and hence the objects of that class) are called **methods**, and the variables that each object has are called **instance variables** (since, like `radius` in the image above, they hold different values for each instance of the class). + +### Objects in R + +This idea of classes serving to collect data and functions (sorry, *methods*) into single objects hasn't been around forever, and over the years different programming languages have captured the idea in different ways. Today, the most popular languages like Java, C++, Python, and even JavaScript have settled on a pattern where a class template is defined within a single chunk of code. If you've used any of these languages, this chunk of JavaScript might look familiar (if not, feel free to just skim): + +``` +// This code is JavaScript, not R... +class Ball(x, y, xs, yx, r, i) { + this.xloc = x; + this.yloc = y; + this.xspeed = xs; + this.yspeed = ys; + this.radius = r; + this.id = i; + + this.move = function() { + this.xloc = this.xloc + this.xspeed; + this.yloc = this.yloc + this.yspeed; + } + + this.display = function() { + ellipse(this.xloc, this.yloc, this.radius, this.radius); + } +} + +var b1 = new Ball(200, 215, 2, -1, 20, "Ball1"); +var b2 = new Ball(107, 165, -3, 3.2, 10, "Ball2"); + +b1.move(); +b1.display(); +b2.move(); +b2.display(); +``` + +This code defines a `Ball` class (blueprint), creates two `Ball` objects `b1` and `b2`, and then asks each in turn to move itself then display itself. + +That's enough JavaScript--this tutorial is supposed to be about R! Although modern versions of R can follow this sort of coding pattern, it hasn't always, since R originally drew inspiration from the statistical language and functional languages Scheme and Lisp. Over the years, R has been graced with *three* different ways to define classes in code. + + 1. S3 Classes - these are the oldest, and the most commonly found in R + 2. S4 Classes - these utilize a hybrid of S3 class concepts, and more modern syntax similar to the JavaScript example above + 3. Reference Classes (RC) - the most recently added, these are very similar to classes defined by Java, JavaScript, Python, C++, etc. + +This particular tutorial focuses on S3 classes, since these are so commonly found in R code. + +### Attributes and Lists + +Before we can write some classes in R, we need to discuss a feature not found in many other languages: attributes. Attributes are a kind of "metadata" that we can attach to any other data. Let's create a random sample of 100 numbers using the `rnorm()` function: +``` +samp <- rnorm(100, mean = 20, sd = 2) +``` +We may want to remember, for later use, what kind of data this is. We can do this with the `attr()` function: +``` +attr(samp, "sampletype") <- "Normal Sample" +``` +Then, later, we can extract this attribute: +``` +stdout$print(attr(samp, "sampletype")) # prints "Normal Sample" +``` +Attributes are how R stores class information. Let's define a numeric vector containing some information for a ball: +``` +b1 <- c(200, 215, 2, -1, 20) # xloc, yloc, xspeed, yspeed, radius +attr(b1, "class") <- "Ball" +``` +Now, as far as R is concerned, `b1` is a `Ball` object! This is because `"class"` is an attribute that R treats specially to hold this information. This is so common that there's a special function just to do this: +``` +class(b1) <- "Ball" +``` + +We can assign attributes to any kind of data in R. Here we've used a numeric vector of 5 numbers to store data about the ball. This isn't too flexible--vectors (created with the `c()` function) can only store one type of data (numbers in this case) as a basic array. Lists, on the other hand, are more flexible: they can hold vectors of different kinds, and even other lists. Maybe we want to store ball data as a location vector, a speed vector, a radius number (actually a vector of length 1 in R), and an id: +``` +b1 <- list(c(200, 215), c(2, -1), 20, "Ball1") +class(b1) <- "Ball" +``` + +Another cool think about lists (and vectors too, actually) is that the elements can have "names": + +``` +b1 <- list(loc = c(200, 215), speed = c(2, -1), + radius = 20, id = "Ball1") + +class(b1) <- "Ball" +``` +This way, we can work with elements by their name, using a `$`-sign. + +``` +stdout$print(b1$loc) # prints 200, 215 +stdout$print(b1$loc[2]) # prints 215 +``` + +We can assign to new entries of a list by using a new name as well: + +``` +b1$volume <- pi * b1$radius ^ 2 # pi is built into R +``` +And, since `loc` and `speed` are both vectors, and R is *vectorized* (most operations work on vectors in an element-by-element manner), we can do something like this to print where the ball will be next: + +``` +stdout$print(b1$loc + b1$speed) # prints 202, 214 +``` + +By the way, **constructor** is the special name for a function that creates an object of the proper form. Usually the function name is the same as the class name: +``` +Ball <- function(x, y, xs, ys, r, i) { + newb <- list(loc = c(x, y), speed = c(xs, ys), + radius = r, id = i) + + class(newb) <- "Ball" + return(newb) +} + +b1 <- Ball(200, 215, 2, -2, 20, "Ball1") +``` + +### Methods + +The above covers how we can collect different kinds of data together, and assign a "class" to that collection. But what about the funtions--the methods--that we want to build to go along with the data? In the simplest case, we can just create a function. here's one that takes a Ball object, add the speed to the location, and returns it: + +``` +move <- function(someball) { + someball$loc <- someball$loc + someball$speed + return(someball) +} +``` +To use it, we can create a Ball object, and call the function. +``` +b1 <- Ball(200, 215, 2, -1, 20, "Ball1") +b2 <- move(b1) + +print(b1$loc) # prints 200, 215 +print(b2$loc) # prints 202, 214 +``` +Notice that we've now got two ball objects, `b1` and `b2`, and they have different locations. This is because most R functions are *pass-by-value*, or, if it helps, "pass-by-copy." This means that inside the `move()` function the variable `someball` is effectively a *copy* of what was passed to the function; the function then modifies this copy and returns it. (Sidenote: many languages are not pass-by-value, and don't make copies in this way. R's Reference Classes operate more similarly to those languages.) + +However, if we want to pretend that we modified the same ball, we can just reassign the `b1` variable: + +``` +b1 <- move(b1) +``` + +R does a lot of work behind the scenes to make this copying as efficient as possible, so try not to stress about it. While we're at it, let's define a `display()` function: + +``` +display <- function(someball) { + ellipse(someball$loc[1], someball$loc[2], + someball$radius, someball$radius) +} +``` + +### Dispatch + +We're getting closer. The trouble here is that there's nothing really "attaching" the `move()` and `display()` functions to `Ball` objects. This is a shame, because they'll only really work with `Ball` objects, not objects of other types. + +To motivate what we mean, we need to come up with some other type of object that could move and be displayed. How about a `Particle` (like a particle of pollen)? Particles will also have an x and y location, but each particle moves by randomly adjusting its location (so it wiggles), and we'll always draw them with a small radius of 2 pixels. + +``` +# Constructor +Particle <- function(x, y) { + newp <- list(loc = c(x, y)) + class(newp) <- "Particle" + return(newp) +} + +# function for moving a particle +move <- function(someparticle) { + someparticle$loc[1] <- someparticle$loc[1] + rnorm(1, mean = 2) + someparticle$loc[2] <- someparticle$loc[2] + rnorm(1, mean = 2) + return(someparticle) +} + +# function for displaying a particle +display <- function(someparticle) { + ellipse(someparticle$loc[1], someparticle$loc[2], 2, 2) +} +``` +Now we can create a couple of particles, have them move, and display them: +``` +p1 <- Particle(400, 400) +p2 <- Particle(500, 500) + +p1 <- move(p1) +p2 <- move(p2) + +display(p1) +display(p2) +``` +But wait! We've defined functions `move()` and `display()`; do these overwrite the ones we wrote earlier for balls? Yes! And that's a problem. + +One solution is to make these functions class-specific (and remember, we call class-specific functions *methods*), by putting the name of the class as part of the function name: +``` +# move method for Ball object +move.Ball <- function(someball) { + someball$loc <- someball$loc + someball$speed + return(someball) +} + +# move method for Particle objects +move.Particle <- function(someparticle) { + someparticle$loc[1] <- someparticle$loc[1] + rnorm(1, mean = 0, sd = 2) + someparticle$loc[2] <- someparticle$loc[2] + rnorm(1, mean = 0, sd = 2) + return(somparticle) +} +``` +(Sidenote: in R, the `.` character isn't very special: it can be used in variable and function names just like any other character. As we'll see though, it is necessary to use this naming scheme for class-specific methods.) + +Now we can say something like +``` +p1 <- move.Particle(p1) +b1 <- move.Ball(b1) +``` +without worry. + +To make our code cleaner, it would be nice if we could define a generic `move()` function, and if the parameter given had class `"Ball"` then it called `move.Ball()`, and if it had class `"Particle"` then it called `move.Particle()`. We could try something like this + +``` +move <- function(x) { + if(attr(x, "class") == "Ball") { + answer <- move.Ball(x) + return(answer) + } else if(attr(x, "class") == "Particle") { + answer <- move.Particle(x) + return(answer) + } +} +``` +That's ok, but it turns out this functionality is built into R. Here's the "official" way to do it. +``` +# R definition for the generic function. +move <- function(x) { + UseMethod("move", x) +} +``` +This function does exactly what we want: it looks at the class of `x`, calls `move.()` instead, and returns the answer. + +This is known as **dispatch**, and a function that "dispatches" to a method based on class information is called a **generic** function. + +----- + +Compared to languages like Java, C++, etc., S3 objects have the same basic stuff--data, class information, and methods. But, whereas Java et al. collect all of this into a single chunk of code, R S3 objects have all of these pieces defined separately. It is the `"class"` attribute that ties them all together conceptually. In Processing.R, many of these pieces should live in the same file (tab) to help with reading. + +### Putting it together + +Finally, let's write a program that simulates two ball objects and two particle objects. Ideally, we would organize Ball code into its own tab in the editor, and Particle code into its own tab, but for now we'll place all of the code into the main script tab. + +Here we will store all of the objects (both Balls and Particles) as elements of a single global `objects` list. + +``` +########################################## +## Constructor and methods for Ball class +########################################## + +# Ball Constructor +Ball <- function(x, y, xs, ys, r, i) { + newb <- list(loc = c(x, y), speed = c(xs, ys), + radius = r, id = i) + + class(newb) <- "Ball" + return(newb) +} + +# Display method for Ball +display.Ball <- function(someball) { + ellipse(someball$loc[1], someball$loc[2], + someball$radius, someball$radius) +} + +# Move method for Ball, returns updated ball +move.Ball <- function(someball) { + someball$loc <- someball$loc + someball$speed + return(someball) +} + +############################################# +## Constructor and methods for Particle class +############################################# + +# Constructor +Particle <- function(x, y) { + newp <- list(loc = c(x, y)) + class(newp) <- "Particle" + return(newp) +} + +# function for displaying a particle +display.Particle <- function(someparticle) { + ellipse(someparticle$loc[1], someparticle$loc[2], 2, 2) +} + +# function for moving a particle +move.Particle <- function(someparticle) { + someparticle$loc[1] <- someparticle$loc[1] + rnorm(1, mean = 0, sd = 2) + someparticle$loc[2] <- someparticle$loc[2] + rnorm(1, mean = 0, sd = 2) + return(someparticle) +} + +##################### +## Generic functions +##################### + +move <- function(x) { + UseMethod("move", x) +} + +display <- function(x) { + UseMethod("display", x) +} + + +##################### +## Main program code +##################### + +# setup size of window +settings <- function() { + size(400, 400) +} + +# create global "objects" list to store Ball and Particle objects +objects <- list() + +# in setup(), add objects to objects list +setup <- function() { + # ball in upper-right, moving leftward & down + objects$b1 <- Ball(350, 50, -1.5, 1.2, 15, "ball1") + # ball in uppr-left, moving rightward & down + objects$b2 <- Ball(50, 50, 1.2, 1.5, 20, "ball2") + # particle in lower-left + objects$p1 <- Particle(50, 350) + # particle in lower-right + objects$p2 <- Particle(350, 350) +} + +# at each frame, draw and update each object +draw <- function() { + background(255, 255, 255) + display(objects$b1) + display(objects$b2) + display(objects$p1) + display(objects$p2) + + objects$b1 <- move(objects$b1) + objects$b2 <- move(objects$b2) + objects$p1 <- move(objects$p1) + objects$p2 <- move(objects$p2) +} +``` + +### Improvements + +One obvious modification would be to use a for-loop to display and move each object; because we use the same generic `move()` and `display()` functions for both types of objects, we needn't be concerned about whether each object is a `Ball` or `Particle`. Here we use `[[]]`-syntax to access list elements by index number. (With vectors we can use `[]`-syntax to identify elements, but with lists `[]` always references a *sub-list*, rather than the element stored at a particular location.) + +``` +draw <- function() { + background(255, 255, 255) + for(i in seq(1:length(objects))) { + display(objects[[i]]) + objects[[i]] <- move(objects[[i]]) + } +} +``` + +Alternatively, we can use R's `lapply()` function, which *applies* a function to each element of a given list. If the function returns something, `lapply()` returns a list of the returned answers. + +``` +draw <- function() { + background(255, 255, 255) + lapply(objects, display) + objects <- lapply(objects, move) +} +``` \ No newline at end of file From fcba4edda587973f927b0132d062317387cdeefa Mon Sep 17 00:00:00 2001 From: Jeremy Douglass Date: Sat, 9 Sep 2017 13:27:19 -0700 Subject: [PATCH 02/12] Tutorials: localize object illustration --- .../objects/imgs/ball_class_and_objects.png | Bin 0 -> 91174 bytes tutorials/objects/index.md | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 tutorials/objects/imgs/ball_class_and_objects.png diff --git a/tutorials/objects/imgs/ball_class_and_objects.png b/tutorials/objects/imgs/ball_class_and_objects.png new file mode 100644 index 0000000000000000000000000000000000000000..5c357ed220c36d1a3fe91a0c88885032f56732c3 GIT binary patch literal 91174 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

ia@-=36XB+ois4-Kgt&dT)mJ32a4p}{q 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 PF#v(5tDnm{r-UW|1Ej%+ literal 0 HcmV?d00001 diff --git a/tutorials/objects/index.md b/tutorials/objects/index.md index ace6fcb..efe7b69 100644 --- a/tutorials/objects/index.md +++ b/tutorials/objects/index.md @@ -8,7 +8,7 @@ An **object** is a more formal way to group all of these pieces together. Object We'll often talk about **classes** as well--a class is the "blueprint" for potentially many objects of the same type. The objects themselves are the actual collections of data built from the class template. Let's consider our ball example, a `Ball` class is code that specifies that all `Ball` objects must have an `xloc`, `yloc`, `xspeed`, `yspeed`, `radius`, and `id`, as well as a function `display()` and a function `move()`. -![enter image description here](https://imgur.com/JfzopbP.png) +![A Ball class is like a general diagram, individual Ball objects are concrete instances of that class](img/ball_class_and_objects.png) In a way, the word `Ball` itself is a bit of data associated with an object, since we need some way to know that an object `x` is a `Ball`, and not, say, a `Car`. From f3463c29d25553036d0361e1995d82bb65995050 Mon Sep 17 00:00:00 2001 From: Jeremy Douglass Date: Sat, 9 Sep 2017 14:06:51 -0700 Subject: [PATCH 03/12] Tutorial: objects -- revisions Minor typos / edits, put asides in blockquotes, clarify S3 as only available class model --- tutorials/objects/index.md | 39 ++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/tutorials/objects/index.md b/tutorials/objects/index.md index efe7b69..7adf9cc 100644 --- a/tutorials/objects/index.md +++ b/tutorials/objects/index.md @@ -10,13 +10,15 @@ We'll often talk about **classes** as well--a class is the "blueprint" for poten ![A Ball class is like a general diagram, individual Ball objects are concrete instances of that class](img/ball_class_and_objects.png) -In a way, the word `Ball` itself is a bit of data associated with an object, since we need some way to know that an object `x` is a `Ball`, and not, say, a `Car`. +In a way, the word `Ball` itself is a bit of data associated with an object, since we need some way to know that an object `x` is a `Ball`, and not, say, a `Car`. In Processing.R we recommend capital initials for class names (e.g. `Ball` rather than `ball`). -Usually we'll use capital initials for class names (e.g. `Ball` rather than `ball`). However, R is not as consistent about this as some other languages, so don't be too surprised to see exceptions to this rule. Some special terminology is also used: functions that that are part of classes (and hence the objects of that class) are called **methods**, and the variables that each object has are called **instance variables** (since, like `radius` in the image above, they hold different values for each instance of the class). +> Note: Capitaliing classes (`Ball`, not `ball`) is a coding convention. It is very consistentlu observed in some language and language modes (like Processing / Java) and less consistent in others (p5.js / Javascript, Processing.R / R). Don't be too surprised to see exceptions to this rule! + +When talking about classes, some special terminology is also used. Functions that that are part of classes (and hence part of the objects of that class) are called **methods**. The variables belonging to each object are called **instance variables**, which hold different values for each _instance_ of the class. In the figure above, `radius` has a different value for each Ball object. ### Objects in R -This idea of classes serving to collect data and functions (sorry, *methods*) into single objects hasn't been around forever, and over the years different programming languages have captured the idea in different ways. Today, the most popular languages like Java, C++, Python, and even JavaScript have settled on a pattern where a class template is defined within a single chunk of code. If you've used any of these languages, this chunk of JavaScript might look familiar (if not, feel free to just skim): +This idea of classes serving to collect data and methods (not functions!) into single objects hasn't been around forever, and over the years different programming languages have captured the idea in different ways. Today, the most popular languages like Java, C++, Python, and even JavaScript have settled on a pattern where a class template is defined within a single chunk of code. If you've used any of these languages, this chunk of JavaScript might look familiar (if not, feel free to just skim): ``` // This code is JavaScript, not R... @@ -47,23 +49,28 @@ b2.move(); b2.display(); ``` -This code defines a `Ball` class (blueprint), creates two `Ball` objects `b1` and `b2`, and then asks each in turn to move itself then display itself. +This code defines a `Ball` class (blueprint), creates two `Ball` objects `b1` and `b2`, and then asks each in turn to move itself then display itself... but that's enough JavaScript--this tutorial is supposed to be about R! Although modern versions of R can follow this same sort of coding pattern, it hasn't always, since R originally drew inspiration from the statistical language and functional languages Scheme and Lisp. -That's enough JavaScript--this tutorial is supposed to be about R! Although modern versions of R can follow this sort of coding pattern, it hasn't always, since R originally drew inspiration from the statistical language and functional languages Scheme and Lisp. Over the years, R has been graced with *three* different ways to define classes in code. +Over the years, R has been graced with *three* different ways to define classes in code. 1. S3 Classes - these are the oldest, and the most commonly found in R 2. S4 Classes - these utilize a hybrid of S3 class concepts, and more modern syntax similar to the JavaScript example above 3. Reference Classes (RC) - the most recently added, these are very similar to classes defined by Java, JavaScript, Python, C++, etc. -This particular tutorial focuses on S3 classes, since these are so commonly found in R code. +**Processing.R supports S3 classes only** -- S3 classes are the most commonly found in R code, and they are what will be covered in this tutorial. + + Note: When looking at R code "in the wild" be careful not to mix S3, S4, and RC classes -- and keep in mind that only S3 is supported in Processing.R. ### Attributes and Lists -Before we can write some classes in R, we need to discuss a feature not found in many other languages: attributes. Attributes are a kind of "metadata" that we can attach to any other data. Let's create a random sample of 100 numbers using the `rnorm()` function: +Before we can write some classes in R, we need to discuss a feature of R that is not found in many other languages: **attributes**. R attributes are a kind of "metadata" that we can attach to any other data. Let's create a random sample of 100 numbers using the `rnorm()` function: + ``` samp <- rnorm(100, mean = 20, sd = 2) ``` -We may want to remember, for later use, what kind of data this is. We can do this with the `attr()` function: + +We may want to remember, for later use, what kind of data this is. We can do this by making up a "sampletype" attribute and adding it to our sample with the `attr()` function: + ``` attr(samp, "sampletype") <- "Normal Sample" ``` @@ -71,7 +78,9 @@ Then, later, we can extract this attribute: ``` stdout$print(attr(samp, "sampletype")) # prints "Normal Sample" ``` -Attributes are how R stores class information. Let's define a numeric vector containing some information for a ball: + +Attributes are also how R stores class information. Let's define a numeric **vector** containing some information for a ball: + ``` b1 <- c(200, 215, 2, -1, 20) # xloc, yloc, xspeed, yspeed, radius attr(b1, "class") <- "Ball" @@ -81,13 +90,14 @@ Now, as far as R is concerned, `b1` is a `Ball` object! This is because `"class" class(b1) <- "Ball" ``` -We can assign attributes to any kind of data in R. Here we've used a numeric vector of 5 numbers to store data about the ball. This isn't too flexible--vectors (created with the `c()` function) can only store one type of data (numbers in this case) as a basic array. Lists, on the other hand, are more flexible: they can hold vectors of different kinds, and even other lists. Maybe we want to store ball data as a location vector, a speed vector, a radius number (actually a vector of length 1 in R), and an id: +We can assign attributes to any kind of data in R. Here we've used a numeric vector of 5 numbers to store data about the ball. This isn't too flexible--vectors (created with the `c()` function) can only store one type of data (numbers in this case) as a basic array. **Lists**, on the other hand, are more flexible: they can hold vectors of different kinds, and even other lists. Maybe we want to store ball data as a location vector, a speed vector, a radius number (actually a vector of length 1 in R), and an id: + ``` b1 <- list(c(200, 215), c(2, -1), 20, "Ball1") class(b1) <- "Ball" ``` -Another cool think about lists (and vectors too, actually) is that the elements can have "names": +Another cool thing about lists (and vectors too, actually) is that list elements can have "names": ``` b1 <- list(loc = c(200, 215), speed = c(2, -1), @@ -215,14 +225,15 @@ move.Particle <- function(someparticle) { return(somparticle) } ``` -(Sidenote: in R, the `.` character isn't very special: it can be used in variable and function names just like any other character. As we'll see though, it is necessary to use this naming scheme for class-specific methods.) -Now we can say something like + Note: In R, unlike in Java or JavaScript, the `.` character isn't very special: it can be used in variable and function names just like any other character. As we'll see though, it is necessary to use this naming scheme for class-specific methods.) + +Now we can say something like this without worry: + ``` p1 <- move.Particle(p1) b1 <- move.Ball(b1) ``` -without worry. To make our code cleaner, it would be nice if we could define a generic `move()` function, and if the parameter given had class `"Ball"` then it called `move.Ball()`, and if it had class `"Particle"` then it called `move.Particle()`. We could try something like this From 2b87fbc9df43f2b69c319da384c0c15c32664eee Mon Sep 17 00:00:00 2001 From: Jeremy Douglass Date: Mon, 11 Sep 2017 09:41:08 -0700 Subject: [PATCH 04/12] spacing --- tutorials/objects/index.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tutorials/objects/index.md b/tutorials/objects/index.md index 7adf9cc..f4e15a0 100644 --- a/tutorials/objects/index.md +++ b/tutorials/objects/index.md @@ -74,7 +74,9 @@ We may want to remember, for later use, what kind of data this is. We can do thi ``` attr(samp, "sampletype") <- "Normal Sample" ``` + Then, later, we can extract this attribute: + ``` stdout$print(attr(samp, "sampletype")) # prints "Normal Sample" ``` @@ -85,7 +87,9 @@ Attributes are also how R stores class information. Let's define a numeric **vec b1 <- c(200, 215, 2, -1, 20) # xloc, yloc, xspeed, yspeed, radius attr(b1, "class") <- "Ball" ``` + Now, as far as R is concerned, `b1` is a `Ball` object! This is because `"class"` is an attribute that R treats specially to hold this information. This is so common that there's a special function just to do this: + ``` class(b1) <- "Ball" ``` @@ -105,6 +109,7 @@ b1 <- list(loc = c(200, 215), speed = c(2, -1), class(b1) <- "Ball" ``` + This way, we can work with elements by their name, using a `$`-sign. ``` @@ -117,6 +122,7 @@ We can assign to new entries of a list by using a new name as well: ``` b1$volume <- pi * b1$radius ^ 2 # pi is built into R ``` + And, since `loc` and `speed` are both vectors, and R is *vectorized* (most operations work on vectors in an element-by-element manner), we can do something like this to print where the ball will be next: ``` @@ -124,6 +130,7 @@ stdout$print(b1$loc + b1$speed) # prints 202, 214 ``` By the way, **constructor** is the special name for a function that creates an object of the proper form. Usually the function name is the same as the class name: + ``` Ball <- function(x, y, xs, ys, r, i) { newb <- list(loc = c(x, y), speed = c(xs, ys), @@ -146,7 +153,9 @@ move <- function(someball) { return(someball) } ``` + To use it, we can create a Ball object, and call the function. + ``` b1 <- Ball(200, 215, 2, -1, 20, "Ball1") b2 <- move(b1) @@ -154,6 +163,7 @@ b2 <- move(b1) print(b1$loc) # prints 200, 215 print(b2$loc) # prints 202, 214 ``` + Notice that we've now got two ball objects, `b1` and `b2`, and they have different locations. This is because most R functions are *pass-by-value*, or, if it helps, "pass-by-copy." This means that inside the `move()` function the variable `someball` is effectively a *copy* of what was passed to the function; the function then modifies this copy and returns it. (Sidenote: many languages are not pass-by-value, and don't make copies in this way. R's Reference Classes operate more similarly to those languages.) However, if we want to pretend that we modified the same ball, we can just reassign the `b1` variable: @@ -197,7 +207,9 @@ display <- function(someparticle) { ellipse(someparticle$loc[1], someparticle$loc[2], 2, 2) } ``` + Now we can create a couple of particles, have them move, and display them: + ``` p1 <- Particle(400, 400) p2 <- Particle(500, 500) @@ -208,9 +220,11 @@ p2 <- move(p2) display(p1) display(p2) ``` + But wait! We've defined functions `move()` and `display()`; do these overwrite the ones we wrote earlier for balls? Yes! And that's a problem. One solution is to make these functions class-specific (and remember, we call class-specific functions *methods*), by putting the name of the class as part of the function name: + ``` # move method for Ball object move.Ball <- function(someball) { @@ -248,13 +262,16 @@ move <- function(x) { } } ``` + That's ok, but it turns out this functionality is built into R. Here's the "official" way to do it. + ``` # R definition for the generic function. move <- function(x) { UseMethod("move", x) } ``` + This function does exactly what we want: it looks at the class of `x`, calls `move.()` instead, and returns the answer. This is known as **dispatch**, and a function that "dispatches" to a method based on class information is called a **generic** function. From 56ec012b0cecee09395510404caabea5d407308c Mon Sep 17 00:00:00 2001 From: Jeremy Douglass Date: Mon, 11 Sep 2017 10:33:57 -0700 Subject: [PATCH 05/12] Embed examples in setup() so Processing.R can run the code as they go; change print statements to built-in --- tutorials/objects/index.md | 107 ++++++++++++++++++++++++++++++------- 1 file changed, 89 insertions(+), 18 deletions(-) diff --git a/tutorials/objects/index.md b/tutorials/objects/index.md index f4e15a0..b4edfb0 100644 --- a/tutorials/objects/index.md +++ b/tutorials/objects/index.md @@ -12,7 +12,7 @@ We'll often talk about **classes** as well--a class is the "blueprint" for poten In a way, the word `Ball` itself is a bit of data associated with an object, since we need some way to know that an object `x` is a `Ball`, and not, say, a `Car`. In Processing.R we recommend capital initials for class names (e.g. `Ball` rather than `ball`). -> Note: Capitaliing classes (`Ball`, not `ball`) is a coding convention. It is very consistentlu observed in some language and language modes (like Processing / Java) and less consistent in others (p5.js / Javascript, Processing.R / R). Don't be too surprised to see exceptions to this rule! +> Note: Capitaliing classes (`Ball`, not `ball`) is a coding convention. It is very consistently observed in some languages (like Processing / Java) and less in others (p5.js / Javascript, Processing.R / R). Don't be too surprised to see exceptions to this rule in R code! When talking about classes, some special terminology is also used. Functions that that are part of classes (and hence part of the objects of that class) are called **methods**. The variables belonging to each object are called **instance variables**, which hold different values for each _instance_ of the class. In the figure above, `radius` has a different value for each Ball object. @@ -49,7 +49,7 @@ b2.move(); b2.display(); ``` -This code defines a `Ball` class (blueprint), creates two `Ball` objects `b1` and `b2`, and then asks each in turn to move itself then display itself... but that's enough JavaScript--this tutorial is supposed to be about R! Although modern versions of R can follow this same sort of coding pattern, it hasn't always, since R originally drew inspiration from the statistical language and functional languages Scheme and Lisp. +This code defines a `Ball` class (blueprint), creates two `Ball` objects `b1` and `b2`, and then asks each in turn to move itself then display itself... but that's enough JavaScript--this tutorial is supposed to be about R! Although modern versions of R can follow this same sort of coding pattern, it hasn't always, since R originally drew inspiration from the statistical language and functional languages Scheme and Lisp. Over the years, R has been graced with *three* different ways to define classes in code. @@ -63,32 +63,58 @@ Over the years, R has been graced with *three* different ways to define classes ### Attributes and Lists -Before we can write some classes in R, we need to discuss a feature of R that is not found in many other languages: **attributes**. R attributes are a kind of "metadata" that we can attach to any other data. Let's create a random sample of 100 numbers using the `rnorm()` function: +Before we can write some classes in R, we need to discuss a feature of R that is not found in many other languages: **attributes**. R attributes are a kind of "metadata" that we can attach to any other data. + +For these examples we will be experimenting with code in a Processing.R sketch inside the `setup` function, and periodically running the sketch to see the results. + +``` +setup <- function() { + exit() +} +```` + +Let's create a random sample of 100 numbers using the `rnorm()` function: ``` samp <- rnorm(100, mean = 20, sd = 2) +print(samp) ``` +> c(17.476707120743, 21.36868260950083, 17.8269424011346, 20.07978640322603, 21.12157543421291,... 100 elements total + We may want to remember, for later use, what kind of data this is. We can do this by making up a "sampletype" attribute and adding it to our sample with the `attr()` function: ``` attr(samp, "sampletype") <- "Normal Sample" ``` -Then, later, we can extract this attribute: +Then, later, we can extract attributes: ``` -stdout$print(attr(samp, "sampletype")) # prints "Normal Sample" +setup <- function() { + samp <- rnorm(100, mean = 20, sd = 2) + attr(samp, "sampletype") <- "Normal Sample" + print(samp) + print("\n") + print(attr(samp, "sampletype")) # Prints "Normal Sample" + exit() +} ``` Attributes are also how R stores class information. Let's define a numeric **vector** containing some information for a ball: ``` -b1 <- c(200, 215, 2, -1, 20) # xloc, yloc, xspeed, yspeed, radius -attr(b1, "class") <- "Ball" +setup <- function() { + b1 <- c(200, 215, 2, -1, 20) # xloc, yloc, xspeed, yspeed, radius + attr(b1, "class") <- "Ball" + print(b1) + print("\n") + print(attr(b1, "class")) + exit() +} ``` -Now, as far as R is concerned, `b1` is a `Ball` object! This is because `"class"` is an attribute that R treats specially to hold this information. This is so common that there's a special function just to do this: +Now, as far as R is concerned, `b1` is a `Ball` object! This is because `"class"` is an attribute that R treats specially to hold this information. This is so common that there's a special function `class()` just to set the class attribute of an object: ``` class(b1) <- "Ball" @@ -101,20 +127,29 @@ b1 <- list(c(200, 215), c(2, -1), 20, "Ball1") class(b1) <- "Ball" ``` -Another cool thing about lists (and vectors too, actually) is that list elements can have "names": +Another cool thing about lists (and vectors too, actually) is that list elements can have names: ``` b1 <- list(loc = c(200, 215), speed = c(2, -1), radius = 20, id = "Ball1") - class(b1) <- "Ball" ``` This way, we can work with elements by their name, using a `$`-sign. ``` -stdout$print(b1$loc) # prints 200, 215 -stdout$print(b1$loc[2]) # prints 215 +setup <- function() { + b1 <- list(loc = c(200, 215), speed = c(2, -1), radius = 20, id = "Ball1") + class(b1) <- "Ball" + print(b1) + print("\n") + print(class(b1)) # prints "Ball" + print("\n") + print(b1$loc) # prints "c(200, 215)" + print("\n") + print(b1$loc[2]) # prints "215.0" + exit() +} ``` We can assign to new entries of a list by using a new name as well: @@ -126,26 +161,29 @@ b1$volume <- pi * b1$radius ^ 2 # pi is built into R And, since `loc` and `speed` are both vectors, and R is *vectorized* (most operations work on vectors in an element-by-element manner), we can do something like this to print where the ball will be next: ``` -stdout$print(b1$loc + b1$speed) # prints 202, 214 +print(b1$loc + b1$speed) # prints 202, 214 ``` By the way, **constructor** is the special name for a function that creates an object of the proper form. Usually the function name is the same as the class name: ``` +setup <- function() { + b1 <- Ball(200, 215, 2, -2, 20, "Ball1") + print(b1) + exit() +} + Ball <- function(x, y, xs, ys, r, i) { newb <- list(loc = c(x, y), speed = c(xs, ys), radius = r, id = i) - class(newb) <- "Ball" return(newb) } - -b1 <- Ball(200, 215, 2, -2, 20, "Ball1") ``` ### Methods -The above covers how we can collect different kinds of data together, and assign a "class" to that collection. But what about the funtions--the methods--that we want to build to go along with the data? In the simplest case, we can just create a function. here's one that takes a Ball object, add the speed to the location, and returns it: +The above covers how we can collect different kinds of data together, and assign a "class" to that collection. But what about the class functions--the methods--that we want to build to go along with the data? In the simplest case, we can just create a function. here's one that takes a Ball object, add the speed to the location, and returns it: ``` move <- function(someball) { @@ -166,7 +204,7 @@ print(b2$loc) # prints 202, 214 Notice that we've now got two ball objects, `b1` and `b2`, and they have different locations. This is because most R functions are *pass-by-value*, or, if it helps, "pass-by-copy." This means that inside the `move()` function the variable `someball` is effectively a *copy* of what was passed to the function; the function then modifies this copy and returns it. (Sidenote: many languages are not pass-by-value, and don't make copies in this way. R's Reference Classes operate more similarly to those languages.) -However, if we want to pretend that we modified the same ball, we can just reassign the `b1` variable: +If we want to modify the `b1` ball we can reassign the variable from the old ball object to the new one. ``` b1 <- move(b1) @@ -181,6 +219,39 @@ display <- function(someball) { } ``` +In order to make this actually display we will need to call if from the Processing.R `draw` loop function. Let's modify our sketch, adding `draw`, removing `exit()` from `setup` so that the draw window will stay open, and adding `noLoop()` to draw so that the sketch will draw once, then pause. + +``` +setup <- function() { + b1 <- Ball(200, 215, 2, -1, 20, "Ball1") + b1 <- move(b1) + print(b1$loc) # prints 200, 215 +} + +draw <- function() { + display(b1) + noLoop() +} + +Ball <- function(x, y, xs, ys, r, i) { + newb <- list(loc = c(x, y), speed = c(xs, ys), + radius = r, id = i) + class(newb) <- "Ball" + return(newb) +} + +move <- function(someball) { + someball$loc <- someball$loc + someball$speed + return(someball) +} + +display <- function(someball) { + ellipse(someball$loc[1], someball$loc[2], + someball$radius, someball$radius) +} +``` + + ### Dispatch We're getting closer. The trouble here is that there's nothing really "attaching" the `move()` and `display()` functions to `Ball` objects. This is a shame, because they'll only really work with `Ball` objects, not objects of other types. From c3ba5f4bacfbec66e90e2c0f18f1954db435e096 Mon Sep 17 00:00:00 2001 From: Jeremy Douglass Date: Mon, 11 Sep 2017 10:40:30 -0700 Subject: [PATCH 06/12] Final code: move main program code to top by convention globals-settings-setup go first in Processing sketches --- tutorials/objects/index.md | 77 +++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/tutorials/objects/index.md b/tutorials/objects/index.md index b4edfb0..0aabd82 100644 --- a/tutorials/objects/index.md +++ b/tutorials/objects/index.md @@ -358,6 +358,44 @@ Finally, let's write a program that simulates two ball objects and two particle Here we will store all of the objects (both Balls and Particles) as elements of a single global `objects` list. ``` +##################### +## Main program code +##################### + +# global "objects" list to store Balls and Particles +objects <- list() + +# settings: create window +settings <- function() { + size(400, 400) +} + +# setup: add objects to objects list +setup <- function() { + # ball in upper-right, moving leftward & down + objects$b1 <- Ball(350, 50, -1.5, 1.2, 15, "ball1") + # ball in uppr-left, moving rightward & down + objects$b2 <- Ball(50, 50, 1.2, 1.5, 20, "ball2") + # particle in lower-left + objects$p1 <- Particle(50, 350) + # particle in lower-right + objects$p2 <- Particle(350, 350) +} + +# draw: each frame, update each object +draw <- function() { + background(255, 255, 255) + display(objects$b1) + display(objects$b2) + display(objects$p1) + display(objects$p2) + + objects$b1 <- move(objects$b1) + objects$b2 <- move(objects$b2) + objects$p1 <- move(objects$p1) + objects$p2 <- move(objects$p2) +} + ########################################## ## Constructor and methods for Ball class ########################################## @@ -417,45 +455,6 @@ move <- function(x) { display <- function(x) { UseMethod("display", x) } - - -##################### -## Main program code -##################### - -# setup size of window -settings <- function() { - size(400, 400) -} - -# create global "objects" list to store Ball and Particle objects -objects <- list() - -# in setup(), add objects to objects list -setup <- function() { - # ball in upper-right, moving leftward & down - objects$b1 <- Ball(350, 50, -1.5, 1.2, 15, "ball1") - # ball in uppr-left, moving rightward & down - objects$b2 <- Ball(50, 50, 1.2, 1.5, 20, "ball2") - # particle in lower-left - objects$p1 <- Particle(50, 350) - # particle in lower-right - objects$p2 <- Particle(350, 350) -} - -# at each frame, draw and update each object -draw <- function() { - background(255, 255, 255) - display(objects$b1) - display(objects$b2) - display(objects$p1) - display(objects$p2) - - objects$b1 <- move(objects$b1) - objects$b2 <- move(objects$b2) - objects$p1 <- move(objects$p1) - objects$p2 <- move(objects$p2) -} ``` ### Improvements From fd2f12c3657d9502916487aadd1c348b35d34090 Mon Sep 17 00:00:00 2001 From: Jeremy Douglass Date: Mon, 11 Sep 2017 10:41:24 -0700 Subject: [PATCH 07/12] Final code: revise comment headings --- tutorials/objects/index.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tutorials/objects/index.md b/tutorials/objects/index.md index 0aabd82..10aeac1 100644 --- a/tutorials/objects/index.md +++ b/tutorials/objects/index.md @@ -397,10 +397,10 @@ draw <- function() { } ########################################## -## Constructor and methods for Ball class +## Ball class ########################################## -# Ball Constructor +# constructor Ball <- function(x, y, xs, ys, r, i) { newb <- list(loc = c(x, y), speed = c(xs, ys), radius = r, id = i) @@ -409,35 +409,35 @@ Ball <- function(x, y, xs, ys, r, i) { return(newb) } -# Display method for Ball +# display method display.Ball <- function(someball) { ellipse(someball$loc[1], someball$loc[2], someball$radius, someball$radius) } -# Move method for Ball, returns updated ball +# move method -- returns updated ball move.Ball <- function(someball) { someball$loc <- someball$loc + someball$speed return(someball) } ############################################# -## Constructor and methods for Particle class +## Particle class ############################################# -# Constructor +# constructor Particle <- function(x, y) { newp <- list(loc = c(x, y)) class(newp) <- "Particle" return(newp) } -# function for displaying a particle +# display method display.Particle <- function(someparticle) { ellipse(someparticle$loc[1], someparticle$loc[2], 2, 2) } -# function for moving a particle +# move method move.Particle <- function(someparticle) { someparticle$loc[1] <- someparticle$loc[1] + rnorm(1, mean = 0, sd = 2) someparticle$loc[2] <- someparticle$loc[2] + rnorm(1, mean = 0, sd = 2) From eb8b00ff4041c6784c26d8ee768981ca36723583 Mon Sep 17 00:00:00 2001 From: Jeremy Douglass Date: Mon, 11 Sep 2017 10:48:54 -0700 Subject: [PATCH 08/12] Add note on no tab support in Processing.R Plus minor line edits for clarity --- tutorials/objects/index.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tutorials/objects/index.md b/tutorials/objects/index.md index 10aeac1..f9b007d 100644 --- a/tutorials/objects/index.md +++ b/tutorials/objects/index.md @@ -343,19 +343,21 @@ move <- function(x) { } ``` -This function does exactly what we want: it looks at the class of `x`, calls `move.()` instead, and returns the answer. +The function `UseMethod()` does exactly what we want: it looks at the class of `x`, calls `move.()` instead, and returns the answer. This is known as **dispatch**, and a function that "dispatches" to a method based on class information is called a **generic** function. ----- -Compared to languages like Java, C++, etc., S3 objects have the same basic stuff--data, class information, and methods. But, whereas Java et al. collect all of this into a single chunk of code, R S3 objects have all of these pieces defined separately. It is the `"class"` attribute that ties them all together conceptually. In Processing.R, many of these pieces should live in the same file (tab) to help with reading. +Compared to languages like Java, C++, etc., R S3 objects have the same basic stuff--data, class information, and methods. But, whereas Java et al. collect all of this into a single chunk of code, R S3 objects have all of these pieces defined separately. It is the `"class"` attribute that ties them all together conceptually. In Processing.R, many of these pieces should live in the same file (or tab) to help with reading. If functions for multiple classes appear in the smae long piece of code, organize them by grouping them together and labeling them with comments. ### Putting it together -Finally, let's write a program that simulates two ball objects and two particle objects. Ideally, we would organize Ball code into its own tab in the editor, and Particle code into its own tab, but for now we'll place all of the code into the main script tab. +Finally, let's write a program that simulates two ball objects and two particle objects. -Here we will store all of the objects (both Balls and Particles) as elements of a single global `objects` list. +> Note: Processing.R currently does not support multiple tabs in the PDE editing window -- all code must appear in the one main tab. Ideally, we would separate our code into three tabs -- the main code first, then the Ball code into its own tab and the Particle code into its own tab. For now we'll place all of the code into different sections of the main script tab and label those sections with code comments. + +We will also store all objects (both Balls and Particles) as elements of a single global `objects` list. ``` ##################### From 0bf938279f381003afdc4212730e8c3bc0b89c85 Mon Sep 17 00:00:00 2001 From: Jeremy Douglass Date: Mon, 11 Sep 2017 11:06:20 -0700 Subject: [PATCH 09/12] Place example ball inside 100x100 viewport so that test sketches can see it by default event before specifying a settings(){ size(x,y) } --- tutorials/objects/index.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tutorials/objects/index.md b/tutorials/objects/index.md index f9b007d..33a5a31 100644 --- a/tutorials/objects/index.md +++ b/tutorials/objects/index.md @@ -40,7 +40,7 @@ class Ball(x, y, xs, yx, r, i) { } } -var b1 = new Ball(200, 215, 2, -1, 20, "Ball1"); +var b1 = new Ball(55, 75, 2, -1, 20, "Ball1"); var b2 = new Ball(107, 165, -3, 3.2, 10, "Ball2"); b1.move(); @@ -105,7 +105,7 @@ Attributes are also how R stores class information. Let's define a numeric **vec ``` setup <- function() { - b1 <- c(200, 215, 2, -1, 20) # xloc, yloc, xspeed, yspeed, radius + b1 <- c(55, 75, 2, -1, 20) # xloc, yloc, xspeed, yspeed, radius attr(b1, "class") <- "Ball" print(b1) print("\n") @@ -123,14 +123,14 @@ class(b1) <- "Ball" We can assign attributes to any kind of data in R. Here we've used a numeric vector of 5 numbers to store data about the ball. This isn't too flexible--vectors (created with the `c()` function) can only store one type of data (numbers in this case) as a basic array. **Lists**, on the other hand, are more flexible: they can hold vectors of different kinds, and even other lists. Maybe we want to store ball data as a location vector, a speed vector, a radius number (actually a vector of length 1 in R), and an id: ``` -b1 <- list(c(200, 215), c(2, -1), 20, "Ball1") +b1 <- list(c(55, 75), c(2, -1), 20, "Ball1") class(b1) <- "Ball" ``` Another cool thing about lists (and vectors too, actually) is that list elements can have names: ``` -b1 <- list(loc = c(200, 215), speed = c(2, -1), +b1 <- list(loc = c(55, 75), speed = c(2, -1), radius = 20, id = "Ball1") class(b1) <- "Ball" ``` @@ -139,13 +139,13 @@ This way, we can work with elements by their name, using a `$`-sign. ``` setup <- function() { - b1 <- list(loc = c(200, 215), speed = c(2, -1), radius = 20, id = "Ball1") + b1 <- list(loc = c(55, 75), speed = c(2, -1), radius = 20, id = "Ball1") class(b1) <- "Ball" print(b1) print("\n") print(class(b1)) # prints "Ball" print("\n") - print(b1$loc) # prints "c(200, 215)" + print(b1$loc) # prints "c(55, 75)" print("\n") print(b1$loc[2]) # prints "215.0" exit() @@ -168,7 +168,7 @@ By the way, **constructor** is the special name for a function that creates an o ``` setup <- function() { - b1 <- Ball(200, 215, 2, -2, 20, "Ball1") + b1 <- Ball(55, 75, 2, -2, 20, "Ball1") print(b1) exit() } @@ -195,10 +195,10 @@ move <- function(someball) { To use it, we can create a Ball object, and call the function. ``` -b1 <- Ball(200, 215, 2, -1, 20, "Ball1") +b1 <- Ball(55, 75, 2, -1, 20, "Ball1") b2 <- move(b1) -print(b1$loc) # prints 200, 215 +print(b1$loc) # prints 55, 75 print(b2$loc) # prints 202, 214 ``` @@ -223,9 +223,9 @@ In order to make this actually display we will need to call if from the Processi ``` setup <- function() { - b1 <- Ball(200, 215, 2, -1, 20, "Ball1") + b1 <- Ball(55, 75, 2, -1, 20, "Ball1") b1 <- move(b1) - print(b1$loc) # prints 200, 215 + print(b1$loc) # prints 55, 75 } draw <- function() { From dcc607404d9840d51fd36d98761d7e3e95be1205 Mon Sep 17 00:00:00 2001 From: Jeremy Douglass Date: Mon, 11 Sep 2017 11:07:44 -0700 Subject: [PATCH 10/12] Final sketch: add simple looper so that contents remain visible even without bounce code --- tutorials/objects/index.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tutorials/objects/index.md b/tutorials/objects/index.md index 33a5a31..ea33293 100644 --- a/tutorials/objects/index.md +++ b/tutorials/objects/index.md @@ -396,6 +396,11 @@ draw <- function() { objects$b2 <- move(objects$b2) objects$p1 <- move(objects$p1) objects$p2 <- move(objects$p2) + + # reset sketch every 300 frames + if(frameCount %% 300 == 0) { + processing$setup() + } } ########################################## From 157ef364ce6f9bb604fae15b133f09701450431e Mon Sep 17 00:00:00 2001 From: Jeremy Douglass Date: Mon, 11 Sep 2017 15:32:41 -0700 Subject: [PATCH 11/12] Typo in image link --- tutorials/objects/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tutorials/objects/index.md b/tutorials/objects/index.md index ea33293..8f0130e 100644 --- a/tutorials/objects/index.md +++ b/tutorials/objects/index.md @@ -8,7 +8,7 @@ An **object** is a more formal way to group all of these pieces together. Object We'll often talk about **classes** as well--a class is the "blueprint" for potentially many objects of the same type. The objects themselves are the actual collections of data built from the class template. Let's consider our ball example, a `Ball` class is code that specifies that all `Ball` objects must have an `xloc`, `yloc`, `xspeed`, `yspeed`, `radius`, and `id`, as well as a function `display()` and a function `move()`. -![A Ball class is like a general diagram, individual Ball objects are concrete instances of that class](img/ball_class_and_objects.png) +![A Ball class is like a general diagram, individual Ball objects are concrete instances of that class](imgs/ball_class_and_objects.png) In a way, the word `Ball` itself is a bit of data associated with an object, since we need some way to know that an object `x` is a `Ball`, and not, say, a `Car`. In Processing.R we recommend capital initials for class names (e.g. `Ball` rather than `ball`). @@ -486,4 +486,4 @@ draw <- function() { lapply(objects, display) objects <- lapply(objects, move) } -``` \ No newline at end of file +``` From 129e97fffc78afedf9adfa584cd26af454a46a2e Mon Sep 17 00:00:00 2001 From: Ce Gao Date: Tue, 12 Sep 2017 17:00:34 +0800 Subject: [PATCH 12/12] objects: Add Signed-off-by: Ce Gao --- tutorials/objects/index.md | 634 +++++++++++++++++-------------------- 1 file changed, 292 insertions(+), 342 deletions(-) diff --git a/tutorials/objects/index.md b/tutorials/objects/index.md index 8f0130e..894fdba 100644 --- a/tutorials/objects/index.md +++ b/tutorials/objects/index.md @@ -8,7 +8,8 @@ An **object** is a more formal way to group all of these pieces together. Object We'll often talk about **classes** as well--a class is the "blueprint" for potentially many objects of the same type. The objects themselves are the actual collections of data built from the class template. Let's consider our ball example, a `Ball` class is code that specifies that all `Ball` objects must have an `xloc`, `yloc`, `xspeed`, `yspeed`, `radius`, and `id`, as well as a function `display()` and a function `move()`. -![A Ball class is like a general diagram, individual Ball objects are concrete instances of that class](imgs/ball_class_and_objects.png) +A Ball class is like a general diagram, individual Ball objects are concrete instances of that class + In a way, the word `Ball` itself is a bit of data associated with an object, since we need some way to know that an object `x` is a `Ball`, and not, say, a `Car`. In Processing.R we recommend capital initials for class names (e.g. `Ball` rather than `ball`). @@ -20,34 +21,34 @@ When talking about classes, some special terminology is also used. Functions tha This idea of classes serving to collect data and methods (not functions!) into single objects hasn't been around forever, and over the years different programming languages have captured the idea in different ways. Today, the most popular languages like Java, C++, Python, and even JavaScript have settled on a pattern where a class template is defined within a single chunk of code. If you've used any of these languages, this chunk of JavaScript might look familiar (if not, feel free to just skim): -``` -// This code is JavaScript, not R... -class Ball(x, y, xs, yx, r, i) { - this.xloc = x; - this.yloc = y; - this.xspeed = xs; - this.yspeed = ys; - this.radius = r; - this.id = i; - - this.move = function() { - this.xloc = this.xloc + this.xspeed; - this.yloc = this.yloc + this.yspeed; - } - - this.display = function() { - ellipse(this.xloc, this.yloc, this.radius, this.radius); - } -} - -var b1 = new Ball(55, 75, 2, -1, 20, "Ball1"); -var b2 = new Ball(107, 165, -3, 3.2, 10, "Ball2"); - -b1.move(); -b1.display(); -b2.move(); -b2.display(); -``` + + // This code is JavaScript, not R... + class Ball(x, y, xs, yx, r, i) { + this.xloc = x; + this.yloc = y; + this.xspeed = xs; + this.yspeed = ys; + this.radius = r; + this.id = i; + + this.move = function() { + this.xloc = this.xloc + this.xspeed; + this.yloc = this.yloc + this.yspeed; + } + + this.display = function() { + ellipse(this.xloc, this.yloc, this.radius, this.radius); + } + } + + var b1 = new Ball(55, 75, 2, -1, 20, "Ball1"); + var b2 = new Ball(107, 165, -3, 3.2, 10, "Ball2"); + + b1.move(); + b1.display(); + b2.move(); + b2.display(); + This code defines a `Ball` class (blueprint), creates two `Ball` objects `b1` and `b2`, and then asks each in turn to move itself then display itself... but that's enough JavaScript--this tutorial is supposed to be about R! Although modern versions of R can follow this same sort of coding pattern, it hasn't always, since R originally drew inspiration from the statistical language and functional languages Scheme and Lisp. @@ -59,7 +60,7 @@ Over the years, R has been graced with *three* different ways to define classes **Processing.R supports S3 classes only** -- S3 classes are the most commonly found in R code, and they are what will be covered in this tutorial. - Note: When looking at R code "in the wild" be careful not to mix S3, S4, and RC classes -- and keep in mind that only S3 is supported in Processing.R. +> Note: When looking at R code "in the wild" be careful not to mix S3, S4, and RC classes -- and keep in mind that only S3 is supported in Processing.R. ### Attributes and Lists @@ -67,190 +68,155 @@ Before we can write some classes in R, we need to discuss a feature of R that is For these examples we will be experimenting with code in a Processing.R sketch inside the `setup` function, and periodically running the sketch to see the results. -``` -setup <- function() { - exit() -} -```` + setup <- function() { + exit() + } Let's create a random sample of 100 numbers using the `rnorm()` function: -``` -samp <- rnorm(100, mean = 20, sd = 2) -print(samp) -``` + samp <- rnorm(100, mean = 20, sd = 2) + print(samp) > c(17.476707120743, 21.36868260950083, 17.8269424011346, 20.07978640322603, 21.12157543421291,... 100 elements total We may want to remember, for later use, what kind of data this is. We can do this by making up a "sampletype" attribute and adding it to our sample with the `attr()` function: -``` -attr(samp, "sampletype") <- "Normal Sample" -``` + attr(samp, "sampletype") <- "Normal Sample" Then, later, we can extract attributes: -``` -setup <- function() { - samp <- rnorm(100, mean = 20, sd = 2) - attr(samp, "sampletype") <- "Normal Sample" - print(samp) - print("\n") - print(attr(samp, "sampletype")) # Prints "Normal Sample" - exit() -} -``` + setup <- function() { + samp <- rnorm(100, mean = 20, sd = 2) + attr(samp, "sampletype") <- "Normal Sample" + print(samp) + print("\n") + print(attr(samp, "sampletype")) # Prints "Normal Sample" + exit() + } Attributes are also how R stores class information. Let's define a numeric **vector** containing some information for a ball: -``` -setup <- function() { - b1 <- c(55, 75, 2, -1, 20) # xloc, yloc, xspeed, yspeed, radius - attr(b1, "class") <- "Ball" - print(b1) - print("\n") - print(attr(b1, "class")) - exit() -} -``` + setup <- function() { + b1 <- c(55, 75, 2, -1, 20) # xloc, yloc, xspeed, yspeed, radius + attr(b1, "class") <- "Ball" + print(b1) + print("\n") + print(attr(b1, "class")) + exit() + } Now, as far as R is concerned, `b1` is a `Ball` object! This is because `"class"` is an attribute that R treats specially to hold this information. This is so common that there's a special function `class()` just to set the class attribute of an object: -``` -class(b1) <- "Ball" -``` + class(b1) <- "Ball" We can assign attributes to any kind of data in R. Here we've used a numeric vector of 5 numbers to store data about the ball. This isn't too flexible--vectors (created with the `c()` function) can only store one type of data (numbers in this case) as a basic array. **Lists**, on the other hand, are more flexible: they can hold vectors of different kinds, and even other lists. Maybe we want to store ball data as a location vector, a speed vector, a radius number (actually a vector of length 1 in R), and an id: -``` -b1 <- list(c(55, 75), c(2, -1), 20, "Ball1") -class(b1) <- "Ball" -``` + b1 <- list(c(55, 75), c(2, -1), 20, "Ball1") + class(b1) <- "Ball" Another cool thing about lists (and vectors too, actually) is that list elements can have names: -``` -b1 <- list(loc = c(55, 75), speed = c(2, -1), - radius = 20, id = "Ball1") -class(b1) <- "Ball" -``` + b1 <- list(loc = c(55, 75), speed = c(2, -1), + radius = 20, id = "Ball1") + class(b1) <- "Ball" This way, we can work with elements by their name, using a `$`-sign. -``` -setup <- function() { - b1 <- list(loc = c(55, 75), speed = c(2, -1), radius = 20, id = "Ball1") - class(b1) <- "Ball" - print(b1) - print("\n") - print(class(b1)) # prints "Ball" - print("\n") - print(b1$loc) # prints "c(55, 75)" - print("\n") - print(b1$loc[2]) # prints "215.0" - exit() -} -``` + setup <- function() { + b1 <- list(loc = c(55, 75), speed = c(2, -1), radius = 20, id = "Ball1") + class(b1) <- "Ball" + print(b1) + print("\n") + print(class(b1)) # prints "Ball" + print("\n") + print(b1$loc) # prints "c(55, 75)" + print("\n") + print(b1$loc[2]) # prints "215.0" + exit() + } We can assign to new entries of a list by using a new name as well: -``` -b1$volume <- pi * b1$radius ^ 2 # pi is built into R -``` + b1$volume <- pi * b1$radius ^ 2 # pi is built into R And, since `loc` and `speed` are both vectors, and R is *vectorized* (most operations work on vectors in an element-by-element manner), we can do something like this to print where the ball will be next: -``` -print(b1$loc + b1$speed) # prints 202, 214 -``` + print(b1$loc + b1$speed) # prints 202, 214 By the way, **constructor** is the special name for a function that creates an object of the proper form. Usually the function name is the same as the class name: -``` -setup <- function() { - b1 <- Ball(55, 75, 2, -2, 20, "Ball1") - print(b1) - exit() -} - -Ball <- function(x, y, xs, ys, r, i) { - newb <- list(loc = c(x, y), speed = c(xs, ys), - radius = r, id = i) - class(newb) <- "Ball" - return(newb) -} -``` + setup <- function() { + b1 <- Ball(55, 75, 2, -2, 20, "Ball1") + print(b1) + exit() + } + + Ball <- function(x, y, xs, ys, r, i) { + newb <- list(loc = c(x, y), speed = c(xs, ys), + radius = r, id = i) + class(newb) <- "Ball" + return(newb) + } ### Methods The above covers how we can collect different kinds of data together, and assign a "class" to that collection. But what about the class functions--the methods--that we want to build to go along with the data? In the simplest case, we can just create a function. here's one that takes a Ball object, add the speed to the location, and returns it: -``` -move <- function(someball) { - someball$loc <- someball$loc + someball$speed - return(someball) -} -``` + move <- function(someball) { + someball$loc <- someball$loc + someball$speed + return(someball) + } To use it, we can create a Ball object, and call the function. -``` -b1 <- Ball(55, 75, 2, -1, 20, "Ball1") -b2 <- move(b1) + b1 <- Ball(55, 75, 2, -1, 20, "Ball1") + b2 <- move(b1) -print(b1$loc) # prints 55, 75 -print(b2$loc) # prints 202, 214 -``` + print(b1$loc) # prints 55, 75 + print(b2$loc) # prints 202, 214 Notice that we've now got two ball objects, `b1` and `b2`, and they have different locations. This is because most R functions are *pass-by-value*, or, if it helps, "pass-by-copy." This means that inside the `move()` function the variable `someball` is effectively a *copy* of what was passed to the function; the function then modifies this copy and returns it. (Sidenote: many languages are not pass-by-value, and don't make copies in this way. R's Reference Classes operate more similarly to those languages.) If we want to modify the `b1` ball we can reassign the variable from the old ball object to the new one. -``` -b1 <- move(b1) -``` + b1 <- move(b1) R does a lot of work behind the scenes to make this copying as efficient as possible, so try not to stress about it. While we're at it, let's define a `display()` function: -``` -display <- function(someball) { - ellipse(someball$loc[1], someball$loc[2], - someball$radius, someball$radius) -} -``` + display <- function(someball) { + ellipse(someball$loc[1], someball$loc[2], + someball$radius, someball$radius) + } In order to make this actually display we will need to call if from the Processing.R `draw` loop function. Let's modify our sketch, adding `draw`, removing `exit()` from `setup` so that the draw window will stay open, and adding `noLoop()` to draw so that the sketch will draw once, then pause. -``` -setup <- function() { - b1 <- Ball(55, 75, 2, -1, 20, "Ball1") - b1 <- move(b1) - print(b1$loc) # prints 55, 75 -} - -draw <- function() { - display(b1) - noLoop() -} - -Ball <- function(x, y, xs, ys, r, i) { - newb <- list(loc = c(x, y), speed = c(xs, ys), - radius = r, id = i) - class(newb) <- "Ball" - return(newb) -} - -move <- function(someball) { - someball$loc <- someball$loc + someball$speed - return(someball) -} - -display <- function(someball) { - ellipse(someball$loc[1], someball$loc[2], - someball$radius, someball$radius) -} -``` - + setup <- function() { + b1 <- Ball(55, 75, 2, -1, 20, "Ball1") + b1 <- move(b1) + print(b1$loc) # prints 55, 75 + } + + draw <- function() { + display(b1) + noLoop() + } + + Ball <- function(x, y, xs, ys, r, i) { + newb <- list(loc = c(x, y), speed = c(xs, ys), + radius = r, id = i) + class(newb) <- "Ball" + return(newb) + } + + move <- function(someball) { + someball$loc <- someball$loc + someball$speed + return(someball) + } + + display <- function(someball) { + ellipse(someball$loc[1], someball$loc[2], + someball$radius, someball$radius) + } ### Dispatch @@ -258,90 +224,78 @@ We're getting closer. The trouble here is that there's nothing really "attaching To motivate what we mean, we need to come up with some other type of object that could move and be displayed. How about a `Particle` (like a particle of pollen)? Particles will also have an x and y location, but each particle moves by randomly adjusting its location (so it wiggles), and we'll always draw them with a small radius of 2 pixels. -``` -# Constructor -Particle <- function(x, y) { - newp <- list(loc = c(x, y)) - class(newp) <- "Particle" - return(newp) -} - -# function for moving a particle -move <- function(someparticle) { - someparticle$loc[1] <- someparticle$loc[1] + rnorm(1, mean = 2) - someparticle$loc[2] <- someparticle$loc[2] + rnorm(1, mean = 2) - return(someparticle) -} - -# function for displaying a particle -display <- function(someparticle) { - ellipse(someparticle$loc[1], someparticle$loc[2], 2, 2) -} -``` + # Constructor + Particle <- function(x, y) { + newp <- list(loc = c(x, y)) + class(newp) <- "Particle" + return(newp) + } + + # function for moving a particle + move <- function(someparticle) { + someparticle$loc[1] <- someparticle$loc[1] + rnorm(1, mean = 2) + someparticle$loc[2] <- someparticle$loc[2] + rnorm(1, mean = 2) + return(someparticle) + } + + # function for displaying a particle + display <- function(someparticle) { + ellipse(someparticle$loc[1], someparticle$loc[2], 2, 2) + } Now we can create a couple of particles, have them move, and display them: -``` -p1 <- Particle(400, 400) -p2 <- Particle(500, 500) + p1 <- Particle(400, 400) + p2 <- Particle(500, 500) -p1 <- move(p1) -p2 <- move(p2) + p1 <- move(p1) + p2 <- move(p2) -display(p1) -display(p2) -``` + display(p1) + display(p2) But wait! We've defined functions `move()` and `display()`; do these overwrite the ones we wrote earlier for balls? Yes! And that's a problem. One solution is to make these functions class-specific (and remember, we call class-specific functions *methods*), by putting the name of the class as part of the function name: -``` -# move method for Ball object -move.Ball <- function(someball) { - someball$loc <- someball$loc + someball$speed - return(someball) -} + # move method for Ball object + move.Ball <- function(someball) { + someball$loc <- someball$loc + someball$speed + return(someball) + } -# move method for Particle objects -move.Particle <- function(someparticle) { - someparticle$loc[1] <- someparticle$loc[1] + rnorm(1, mean = 0, sd = 2) - someparticle$loc[2] <- someparticle$loc[2] + rnorm(1, mean = 0, sd = 2) - return(somparticle) -} -``` + # move method for Particle objects + move.Particle <- function(someparticle) { + someparticle$loc[1] <- someparticle$loc[1] + rnorm(1, mean = 0, sd = 2) + someparticle$loc[2] <- someparticle$loc[2] + rnorm(1, mean = 0, sd = 2) + return(somparticle) + } - Note: In R, unlike in Java or JavaScript, the `.` character isn't very special: it can be used in variable and function names just like any other character. As we'll see though, it is necessary to use this naming scheme for class-specific methods.) +> Note: In R, unlike in Java or JavaScript, the `.` character isn't very special: it can be used in variable and function names just like any other character. As we'll see though, it is necessary to use this naming scheme for class-specific methods.) Now we can say something like this without worry: -``` -p1 <- move.Particle(p1) -b1 <- move.Ball(b1) -``` + p1 <- move.Particle(p1) + b1 <- move.Ball(b1) To make our code cleaner, it would be nice if we could define a generic `move()` function, and if the parameter given had class `"Ball"` then it called `move.Ball()`, and if it had class `"Particle"` then it called `move.Particle()`. We could try something like this -``` -move <- function(x) { - if(attr(x, "class") == "Ball") { - answer <- move.Ball(x) - return(answer) - } else if(attr(x, "class") == "Particle") { - answer <- move.Particle(x) - return(answer) - } -} -``` + move <- function(x) { + if(attr(x, "class") == "Ball") { + answer <- move.Ball(x) + return(answer) + } else if(attr(x, "class") == "Particle") { + answer <- move.Particle(x) + return(answer) + } + } That's ok, but it turns out this functionality is built into R. Here's the "official" way to do it. -``` -# R definition for the generic function. -move <- function(x) { - UseMethod("move", x) -} -``` + # R definition for the generic function. + move <- function(x) { + UseMethod("move", x) + } The function `UseMethod()` does exactly what we want: it looks at the class of `x`, calls `move.()` instead, and returns the answer. @@ -359,131 +313,127 @@ Finally, let's write a program that simulates two ball objects and two particle We will also store all objects (both Balls and Particles) as elements of a single global `objects` list. -``` -##################### -## Main program code -##################### - -# global "objects" list to store Balls and Particles -objects <- list() - -# settings: create window -settings <- function() { - size(400, 400) -} - -# setup: add objects to objects list -setup <- function() { - # ball in upper-right, moving leftward & down - objects$b1 <- Ball(350, 50, -1.5, 1.2, 15, "ball1") - # ball in uppr-left, moving rightward & down - objects$b2 <- Ball(50, 50, 1.2, 1.5, 20, "ball2") - # particle in lower-left - objects$p1 <- Particle(50, 350) - # particle in lower-right - objects$p2 <- Particle(350, 350) -} - -# draw: each frame, update each object -draw <- function() { - background(255, 255, 255) - display(objects$b1) - display(objects$b2) - display(objects$p1) - display(objects$p2) - - objects$b1 <- move(objects$b1) - objects$b2 <- move(objects$b2) - objects$p1 <- move(objects$p1) - objects$p2 <- move(objects$p2) - - # reset sketch every 300 frames - if(frameCount %% 300 == 0) { - processing$setup() - } -} - -########################################## -## Ball class -########################################## - -# constructor -Ball <- function(x, y, xs, ys, r, i) { - newb <- list(loc = c(x, y), speed = c(xs, ys), - radius = r, id = i) - - class(newb) <- "Ball" - return(newb) -} - -# display method -display.Ball <- function(someball) { - ellipse(someball$loc[1], someball$loc[2], - someball$radius, someball$radius) -} - -# move method -- returns updated ball -move.Ball <- function(someball) { - someball$loc <- someball$loc + someball$speed - return(someball) -} - -############################################# -## Particle class -############################################# - -# constructor -Particle <- function(x, y) { - newp <- list(loc = c(x, y)) - class(newp) <- "Particle" - return(newp) -} - -# display method -display.Particle <- function(someparticle) { - ellipse(someparticle$loc[1], someparticle$loc[2], 2, 2) -} - -# move method -move.Particle <- function(someparticle) { - someparticle$loc[1] <- someparticle$loc[1] + rnorm(1, mean = 0, sd = 2) - someparticle$loc[2] <- someparticle$loc[2] + rnorm(1, mean = 0, sd = 2) - return(someparticle) -} - -##################### -## Generic functions -##################### - -move <- function(x) { - UseMethod("move", x) -} - -display <- function(x) { - UseMethod("display", x) -} -``` + ##################### + ## Main program code + ##################### + + # global "objects" list to store Balls and Particles + objects <- list() + + # settings: create window + settings <- function() { + size(400, 400) + } + + # setup: add objects to objects list + setup <- function() { + # ball in upper-right, moving leftward & down + objects$b1 <- Ball(350, 50, -1.5, 1.2, 15, "ball1") + # ball in uppr-left, moving rightward & down + objects$b2 <- Ball(50, 50, 1.2, 1.5, 20, "ball2") + # particle in lower-left + objects$p1 <- Particle(50, 350) + # particle in lower-right + objects$p2 <- Particle(350, 350) + } + + # draw: each frame, update each object + draw <- function() { + background(255, 255, 255) + display(objects$b1) + display(objects$b2) + display(objects$p1) + display(objects$p2) + + objects$b1 <- move(objects$b1) + objects$b2 <- move(objects$b2) + objects$p1 <- move(objects$p1) + objects$p2 <- move(objects$p2) + + # reset sketch every 300 frames + if(frameCount %% 300 == 0) { + processing$setup() + } + } + + ########################################## + ## Ball class + ########################################## + + # constructor + Ball <- function(x, y, xs, ys, r, i) { + newb <- list(loc = c(x, y), speed = c(xs, ys), + radius = r, id = i) + + class(newb) <- "Ball" + return(newb) + } + + # display method + display.Ball <- function(someball) { + ellipse(someball$loc[1], someball$loc[2], + someball$radius, someball$radius) + } + + # move method -- returns updated ball + move.Ball <- function(someball) { + someball$loc <- someball$loc + someball$speed + return(someball) + } + + ############################################# + ## Particle class + ############################################# + + # constructor + Particle <- function(x, y) { + newp <- list(loc = c(x, y)) + class(newp) <- "Particle" + return(newp) + } + + # display method + display.Particle <- function(someparticle) { + ellipse(someparticle$loc[1], someparticle$loc[2], 2, 2) + } + + # move method + move.Particle <- function(someparticle) { + someparticle$loc[1] <- someparticle$loc[1] + rnorm(1, mean = 0, sd = 2) + someparticle$loc[2] <- someparticle$loc[2] + rnorm(1, mean = 0, sd = 2) + return(someparticle) + } + + ##################### + ## Generic functions + ##################### + + move <- function(x) { + UseMethod("move", x) + } + + display <- function(x) { + UseMethod("display", x) + } ### Improvements One obvious modification would be to use a for-loop to display and move each object; because we use the same generic `move()` and `display()` functions for both types of objects, we needn't be concerned about whether each object is a `Ball` or `Particle`. Here we use `[[]]`-syntax to access list elements by index number. (With vectors we can use `[]`-syntax to identify elements, but with lists `[]` always references a *sub-list*, rather than the element stored at a particular location.) -``` -draw <- function() { - background(255, 255, 255) - for(i in seq(1:length(objects))) { - display(objects[[i]]) - objects[[i]] <- move(objects[[i]]) - } -} -``` + + draw <- function() { + background(255, 255, 255) + for(i in seq(1:length(objects))) { + display(objects[[i]]) + objects[[i]] <- move(objects[[i]]) + } + } + Alternatively, we can use R's `lapply()` function, which *applies* a function to each element of a given list. If the function returns something, `lapply()` returns a list of the returned answers. -``` -draw <- function() { - background(255, 255, 255) - lapply(objects, display) - objects <- lapply(objects, move) -} -``` + draw <- function() { + background(255, 255, 255) + lapply(objects, display) + objects <- lapply(objects, move) + }