<p>Remembering that R works well on vectors, a first step is to think of 'Words' rather than 'Word'</p>

<pre><code>## constructor, accessors, subset (also need [[, [&lt;-, [[&lt;- methods)
.Words &lt;- setClass("Words",
    representation(words="character", parts="character"))
words &lt;- function(x) x@words
parts &lt;- function(x) x@parts
setMethod("length", "Words", function(x) length(words(x)))
setMethod("[", c("Words", "ANY", "missing"), function(x, i, j, ...) {
    initialize(x, words=words(x)[i], parts=parts(x)[i], ...)
})

## validity
setValidity("Words", function(object) {
    if (length(words(object)) == length(parts(object)))
        NULL
    else
        "'words()' and 'parts()' are not the same length"
})
</code></pre>

<p>@nicola's suggestion that one have a list of words has been formalized in the <a href="http://bioconductor.org/packages/release/bioc/html/IRanges.html" rel="nofollow">IRanges</a> package (actually, <a href="http://bioconductor.org/packages/devel/bioc/html/S4Vectors.html" rel="nofollow">S4Vectors</a> in the 'devel' / 3.0 branch of Bioconductor), where a 'SimpleList' takes the 'naive' approach of requiring all elements of the list to have the same class, whereas a 'CompressedList' has similar behavior but actually is implemented as a vector-like object (one with a length(), [, and [[ methods) that is 'partitioned' (either by end or width) into groups.</p>

<pre><code>library(IRanges)
.Sentences = setClass("Sentences",
    contains="CompressedList",    
    prototype=c(elementType="Words"))
</code></pre>

<p>One would then write a more user-friendly constructor, but the basic functionality is</p>

<pre><code>## 0 Sentences
.Sentences()
## 1 sentence of 0 words
.Sentences(unlistData=.Words(), partitioning=PartitioningByEnd(0))
## 3 sentences of 2, 0, and 3 words
s3 &lt;- .Sentences(unlistData=.Words(words=letters[1:5], parts=LETTERS[1:5]), 
    partitioning=PartitioningByEnd(c(2, 2, 5)))
</code></pre>

<p>leading to</p>

<pre><code>&gt; s3[[1]]
An object of class "Words"
Slot "word":
[1] "a" "b"

Slot "part":
[1] "A" "B"

&gt; s3[[2]]
An object of class "Words"
Slot "word":
character(0)

Slot "part":
character(0)

&gt; s3[[3]]
An object of class "Words"
Slot "word":
[1] "c" "d" "e"

Slot "part":
[1] "C" "D" "E"
</code></pre>

<p>Notice that some typical operations are fast because they can operate on the 'unlisted' elements without creating or destroying S4 instances, e.g., coercing all 'words' to upper case</p>

<pre><code>setMethod(toupper, "Words", function(x) { x@word &lt;- toupper(x@word); x })
setMethod(toupper, "Sentences", function(x) relist(toupper(unlist(x)), x))
</code></pre>

<p>This is 'fast' for large collections of sentences because unlist / relist is really on a slot access and creation of a single instance of 'Words'. <a href="http://fr.arxiv.org/abs/1409.2864" rel="nofollow">Scalable Genomics with R and Bioconductor</a> outlines this and other strategies.</p>

<p>In an answer @nicola says 'R is not perfectly suited for OO programming style' but it's probably more helpful to realize that R's S4 object oriented style differs from C++ and Java, just as R differs from C. In particular it's really valuable to continue thinking in terms of vectors when working with S4 -- Words rather than Word, People rather than Person...</p>
How can I make slot to be filled with multiple same-type objects in R?
<p>Let's say I want to define two classes classes, <code>Sentence</code> and <code>Word</code>. Each word object has a character string and a part of speech (pos). Each sentence contains some number of words and has an additional slot for data.</p>

<p>The <code>Word</code> class is straightforward to define.</p>

<pre><code>wordSlots &lt;- list(word = "character", pos = "character")
wordProto &lt;- list(word = "", pos = "")
setClass("Word", slots = wordSlots, prototype = wordProto)    
Word &lt;- function(word, pos) new("Word", word=word, pos=pos)
</code></pre>

<p>Now I want to make a <code>Sentence</code> class which can contain some <code>Word</code>s and some numerical data.</p>

<p>If I define the <code>Sentence</code> class as so:</p>

<pre><code>sentenceSlots &lt;- list(words = "Word", stats = "numeric")
sentenceProto &lt;- list(words = Word(), stats = 0)
setClass("Sentence", slots = sentenceSlots, prototype = sentenceProto)
</code></pre>

<p>Then the sentence can contain only one word. I could obviously define it with many slots, one for each word, but then it will be limited in length.</p>

<p>However, if I define the <code>Sentence</code> class like this:</p>

<pre><code>sentenceSlots &lt;- list(words = "list", stats = "numeric")
sentenceProto &lt;- list(words = list(Word()), stats = 0)
setClass("Sentence", slots = sentenceSlots, prototype = sentenceProto)
</code></pre>

<p>it can contain as many words as I want, but the slot <code>words</code> can contain objects which are not of the class <code>Word</code>.</p>

<p>Is there a way to accomplish this? This would be similar to the C++ thing where you can have a vector of objects of the same type.</p>