Kestrel Exams kestrel logo KESTREL EXAMSPRACTICE TO PASS
Java19 min readCode verified

Generics: the <T> in generic methods and classes

Generics let you write one method or class that works for many types while the compiler still checks every one. This guide covers what <T> means, generic methods, bounded generics with extends, generic classes, and the few things generics will not let you do. Every listing was compiled and run on OpenJDK 21.

Practice this topic in the free app →All Java guides

A lost-and-found desk with labeled bins#

Picture the lost-and-found desk at a busy bus station. Behind the counter is a wall of identical plastic bins, each with a blank label slot. The clerk writes “Scarves” on one and “Keys” on another. From then on, each bin holds only that kind of thing. (Every lost-and-found on earth also has one bin that is mostly umbrellas.)

Java generics work the same way. You write a method or class once, with a blank for a type, and whoever uses it fills in the blank. The blank is a type parameter, usually one capital letter inside angle brackets: <T>. The real type that fills it in, such as String, is the type argument. It stands in for a type the way a parameter stands in for a value.

You have done this before: ArrayList<String> fills in the blank of the library class ArrayList<E>, and the compiler reads that label. This guide builds one program, LostAndFound, for the desk, starting with its log of item descriptions:

LostAndFound.java
import java.util.ArrayList;

public class LostAndFound {
    public static void main(String[] args) {
        ArrayList<String> log = new ArrayList<>();
        log.add("black umbrella");
        log.add(42);
    }
}
LostAndFound.java:7: error: incompatible types: int cannot be converted to String
        log.add(42);
                ^
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
1 error

The list is labeled String, so the number 42 is refused before the program ever runs. That is the point of generics: write the code once, and let the compiler check every type that goes in and comes out.

One method per type, or just use Object?#

Start from a shape you already know. The desk keeps a shelf of item names, and you want a method that prints a shelf on one line:

LostAndFound.java
public class LostAndFound {
    public static void printShelf(String[] shelf) {
        String line = "Shelf:";
        for (String item : shelf) {
            line += " " + item;
        }
        System.out.println(line);
    }

    public static void main(String[] args) {
        String[] items = {"umbrella", "scarf", "keys"};
        printShelf(items);
    }
}
Shelf: umbrella scarf keys

Now the desk adds a shelf of tag numbers, an Integer[]. Copying the method with Integer in place of String works, but every bug fix must then be made twice.

There is an obvious shortcut. Every class is a kind of Object, and Java lets an array of Strings go where an Object[] is expected. So one method that takes Object[] accepts any shelf. Here is that idea in a method that hands back the first item on a shelf.

Try it first

firstItem returns an Object, so the caller must cast it, which means telling Java “treat this value as a String”. Look at the line that casts the first tag to a String. Does it compile? If so, what happens when it runs?

Show the answer

It compiles. The compiler only knows the result is some Object, which might be a String, so it trusts your cast. At run time the value is an Integer, and the cast fails with a ClassCastException.

LostAndFound.java
public class LostAndFound {
    public static Object firstItem(Object[] shelf) {
        return shelf[0];
    }

    public static void main(String[] args) {
        String[] items = {"umbrella", "scarf", "keys"};
        Integer[] tags = {104, 101, 103};
        String first = (String) firstItem(items);    // cast needed
        System.out.println("First item: " + first);
        String wrong = (String) firstItem(tags);     // compiles, then fails
        System.out.println("Never printed: " + wrong);
    }
}
First item: umbrella
Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')
	at LostAndFound.main(LostAndFound.java:11)

The method threw away the label, so every result needs a cast, and a wrong cast is found only at run time. Java collections worked this way before Java 5. (Python lists hold anything too, and you find out what is inside when you use it. Java wants the label up front.)

The one change: a type parameter#

Go back to the String version. A generic method is the same method with one change: announce a type parameter, <T>, then write T wherever you wrote String.

The announcement goes in one exact spot: after the modifiers (public static) and just before the return type. Read public static <T> T firstItem(T[] shelf) as “for any type T, return a T from an array of T”. The first T declares the type parameter. Every later T uses it.

LostAndFound.java
public class LostAndFound {
    public static <T> void printShelf(T[] shelf) {
        String line = "Shelf:";
        for (T item : shelf) {
            line += " " + item;
        }
        System.out.println(line);
    }

    public static <T> T firstItem(T[] shelf) {
        return shelf[0];
    }

    public static <T> void swap(T[] shelf, int i, int j) {
        T temp = shelf[i];
        shelf[i] = shelf[j];
        shelf[j] = temp;
    }

    public static void main(String[] args) {
        String[] items = {"umbrella", "scarf", "keys"};
        Integer[] tags = {104, 101, 103};
        printShelf(items);
        printShelf(tags);
        String first = firstItem(items);             // no cast
        int firstTag = firstItem(tags);
        System.out.println(first + " has tag " + firstTag);
        swap(items, 0, 2);
        printShelf(items);
    }
}
Shelf: umbrella scarf keys
Shelf: 104 101 103
umbrella has tag 104
Shelf: keys scarf umbrella

One printShelf printed both shelves, and neither firstItem call needed a cast. The Integer was unboxed, meaning converted to a plain int automatically. swap works on any shelf; index 2 is the third item, since indexes start at 0.

Now the mistake that crashed the Object version:

LostAndFound.java
public class LostAndFound {
    public static <T> T firstItem(T[] shelf) {
        return shelf[0];
    }

    public static void main(String[] args) {
        Integer[] tags = {104, 101, 103};
        String wrong = firstItem(tags);
        System.out.println("Never printed: " + wrong);
    }
}
LostAndFound.java:8: error: incompatible types: inference variable T has incompatible bounds
        String wrong = firstItem(tags);
                                ^
    upper bounds: String,Object
    lower bounds: Integer
  where T is a type-variable:
    T extends Object declared in method <T>firstItem(T[])
1 error

The run-time crash is now a compile error, read in the next section.

Trap check: where does <T> go?

For a generic method, <T> goes before the return type, every time. Leave it out, as in public static T firstItem(T[] shelf), and Java assumes T is a class you forgot to write. You get cannot find symbol with symbol: class T, once for each T in the heading. That message means: look for a missing <T>.

How Java fills in T: type inference#

You never wrote <String> when calling printShelf. Java worked out what T had to be, which is called type inference. It collects rules that T must obey, called bounds in the messages, then looks for one type that obeys them all.

In the last error, the argument tags made Integer a lower bound: T must be Integer or a type above it. The variable receiving the result, called the target type, made String an upper bound: T must be String or below. (Object is listed because it bounds every plain T.) No type is both “Integer or above” and “String or below”, so the result is incompatible bounds.

You can also name the type yourself with an explicit type argument. It goes after the dot and just before the method name: LostAndFound.<Integer>firstItem(tags). For a static method, the class name and dot are required. Recognize it on an exam.

Inference gets more interesting when two arguments share one T:

LostAndFound.java
public class LostAndFound {
    public static <T> T firstItem(T[] shelf) {
        return shelf[0];
    }

    public static <T> T choose(boolean takeFirst, T a, T b) {
        if (takeFirst) {
            return a;
        }
        return b;
    }

    public static void main(String[] args) {
        Integer[] tags = {104, 101, 103};
        Integer tag = LostAndFound.<Integer>firstItem(tags);  // T named by hand
        String item = choose(false, "scarf", "keys");        // T is String
        Object either = choose(true, "scarf", 104);          // String and Integer
        System.out.println(tag + " " + item + " " + either);
    }
}
104 keys scarf
Try it first

In choose(true, "scarf", 104), takeFirst is true, so the value returned is the String "scarf". Would String item = choose(true, "scarf", 104); compile?

Show the answer

No. Inference happens at compile time and only looks at types, never at true or false. T must accept a String and an Integer, so it can never be String. javac reports inferred type does not conform to upper bound(s). The Object variable in the listing accepts the result, which is why that line compiled.

Bounded generic methods: T extends something#

The desk wants the largest item on a shelf: the newest tag, or the last name alphabetically. Java compares objects with compareTo.

Try it first

Write largest with a plain <T> and call shelf[i].compareTo(best) inside it. Will it compile?

Show the answer

No. A plain T could be any type, so Java only allows what every object has: the methods of Object. javac reports cannot find symbol for compareTo, with location: class Object.

The fix is a bound, also called an upper bound. It limits which types may fill the blank, and in exchange it lets you call their methods. Write <T extends Comparable<T>>: “any type T that can be compared with other Ts”. Comparable is itself generic, declared Comparable<T>, which is why T appears twice. This is a bounded type parameter. A class implements Comparable, but a bound always says extends, for classes and interfaces alike.

A second common bound is <T extends Number>. Number is the parent class of Integer, Double and the other wrapper classes (class versions of the primitive number types). It gives them all doubleValue().

Try it first

Predict all four lines. The cash is 20, 5 and 40 dollars; the weights are 0.5, 1.25 and 0.25 kilograms. Watch the return type of total.

Show the answerNewest tag: 104, Last by name: umbrella, Cash found: 65.0 and Total weight: 2.0. The cash prints 65.0 because total returns a double.
LostAndFound.java
public class LostAndFound {
    public static <T extends Comparable<T>> T largest(T[] shelf) {
        T best = shelf[0];                           // assume the first is largest
        for (int i = 1; i < shelf.length; i++) {
            if (shelf[i].compareTo(best) > 0) {
                best = shelf[i];
            }
        }
        return best;
    }

    public static <T extends Number> double total(T[] values) {
        double sum = 0;
        for (T v : values) {
            sum += v.doubleValue();                  // every Number has this
        }
        return sum;
    }

    public static void main(String[] args) {
        Integer[] tags = {104, 101, 103};
        String[] items = {"umbrella", "scarf", "keys"};
        System.out.println("Newest tag: " + largest(tags));
        System.out.println("Last by name: " + largest(items));

        Integer[] cash = {20, 5, 40};                // dollars found in wallets
        Double[] weights = {0.5, 1.25, 0.25};        // kilograms
        System.out.println("Cash found: " + total(cash));
        System.out.println("Total weight: " + total(weights));
    }
}
Newest tag: 104
Last by name: umbrella
Cash found: 65.0
Total weight: 2.0

Does this make sense? 20 + 5 + 40 is 65, with .0 because of the double, and a total below the biggest single value would be obviously wrong. Keep this check when an AI tool hands you an answer too: decide roughly what the result should be, then compare.

One largest served Integers and Strings, and one total served Integers and Doubles. Outside a story, their parameters would get general names like values.

The bound also rejects types. Calling total(items) with the String shelf fails with inference variable T has incompatible bounds. The upper bound Number comes from your bound and the lower bound String comes from the argument. You tried to put a String in a slot labeled “numbers only”.

Trap check: does the loop start at 0 or 1?

largest starts best at shelf[0] and loops from i = 1. Shrink it to check. With one tag, {7}, the test 1 < 1 is false, the loop runs zero times, and it returns 7. Correct. With an empty shelf, shelf[0] throws ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0. An empty shelf has no largest item, so check shelf.length first.

Generic classes: one Bin class, many bins#

A bin keeps its label for as long as it exists. That is a generic class: an ordinary class with one change, a type parameter right after the class name, class Bin<T>. Inside, fields, parameters and return values can use T, and methods do not announce it again. Each Bin keeps its items in an ArrayList<T>, so a Bin<String> holds an ArrayList<String>.

Try it first

Tickets 101 and 1000 go into the tickets bin. What should contains(101) and contains(1000) print? Read contains before you look.

Show the answer

Both should print true. On this run, 1000 does not. The reason is below the output.

LostAndFound.java
import java.util.ArrayList;

class Bin<T> {
    private String label;
    private ArrayList<T> items = new ArrayList<>();

    public Bin(String label) {
        this.label = label;
    }

    public void add(T item) {
        items.add(item);
    }

    public T get(int index) {
        return items.get(index);
    }

    public boolean contains(T target) {
        for (T item : items) {
            if (item == target) {                    // on purpose: see below
                return true;
            }
        }
        return false;
    }

    @Override
    public String toString() {
        return label + " " + items;
    }
}

public class LostAndFound {
    public static void main(String[] args) {
        Bin<String> scarves = new Bin<>("Scarves");
        scarves.add("red wool");
        scarves.add("striped");
        Bin<Integer> tickets = new Bin<Integer>("Tickets");
        tickets.add(101);
        tickets.add(1000);

        String first = scarves.get(0);               // no cast
        int ticket = tickets.get(1);
        System.out.println(scarves);
        System.out.println(tickets);
        System.out.println(first + " / ticket " + ticket);
        System.out.println("Has 101? " + tickets.contains(101));
        System.out.println("Has 1000? " + tickets.contains(1000));
    }
}
Scarves [red wool, striped]
Tickets [101, 1000]
red wool / ticket 1000
Has 101? true
Has 1000? false

One Bin class made two kinds of bin, and each get needed no cast.

The last line is wrong on purpose, so you meet it here and not at 2 a.m. before a deadline. T values are always objects, and == on objects asks “same object?”, not “same value?”. Each Integer here was autoboxed, meaning converted automatically from an int into an object. Java guarantees one shared object only from -128 to 127. Above that it depends on the JVM. On a standard setup, like the run above, the stored 1000 and the searched-for 1000 are different objects, so == can say true or false. Only equals is safe.

Trap check: == or equals?

Every time you compare two T values, use equals. Change the one line in contains to if (item.equals(target)), and the last line becomes:

Has 1000? true

Now the creation lines. new Bin<Integer>("Tickets") repeats the type. new Bin<>("Scarves") leaves the angle brackets empty, and inference fills them from the variable on the left. The empty pair is nicknamed the diamond operator. Both are correct; most programmers use the diamond.

Leaving the angle brackets off completely, new Bin("Scarves"), makes a raw type, a Bin with no label at all. The compiler cannot check that line, so it adds a note about “unchecked or unsafe operations”. Declare the variable as plain Bin and every use of it goes unchecked.

Two type parameters, and a bounded class#

Whoever hands in an item gets a claim ticket. A claim joins two values of possibly different types, so it gets two type parameters, separated by a comma: class Claim<K, V>.

LostAndFound.java
class Claim<K, V> {
    private K ticket;
    private V item;

    public Claim(K ticket, V item) {
        this.ticket = ticket;
        this.item = item;
    }

    public K getTicket() {
        return ticket;
    }

    public V getItem() {
        return item;
    }

    @Override
    public String toString() {
        return "#" + ticket + " = " + item;
    }
}

public class LostAndFound {
    public static void main(String[] args) {
        Claim<Integer, String> c1 = new Claim<>(104, "umbrella");
        Claim<String, Double> c2 = new Claim<>("B-7", 1.25);
        int number = c1.getTicket();
        String what = c1.getItem();
        System.out.println(number + " is the " + what);
        System.out.println(c1);
        System.out.println(c2);
    }
}
104 is the umbrella
#104 = umbrella
#B-7 = 1.25

One Claim class paired an Integer with a String, and a String with a Double. c1.getItem() is a String because V is String for c1. The diamond filled in both type arguments.

A class can take a bound too. Inside class WeightLog<T extends Number>, the bound allows weight.doubleValue(). Outside, WeightLog<Double> is fine, but WeightLog<String> words; fails with type argument String is not within bounds of type-variable T.

By convention, type parameters are single capital letters: T for type, E for element, K and V for key and value. Any legal name compiles, but one letter shows at a glance that it is not a real class. A general two-slot class is often just called Pair<A, B>.

No primitives as type arguments#

Here is why the tag shelf was never an int[]:

LostAndFound.java
import java.util.ArrayList;

class Bin<T> {
    private ArrayList<T> items = new ArrayList<>();

    public void add(T item) {
        items.add(item);
    }
}

public class LostAndFound {
    public static void main(String[] args) {
        Bin<int> tickets = new Bin<>();
    }
}
LostAndFound.java:13: error: unexpected type
        Bin<int> tickets = new Bin<>();
            ^
  required: reference
  found:    int
1 error

A type argument must be a reference type: a class, an interface or an array type. The eight primitive types, such as int, double, char and boolean, are not allowed.

Trap check: int or Integer?

Every time you write a type argument, check it is not a primitive. Use the wrapper class: Integer, Double, Character, Boolean. tickets.add(101) still works, because Java autoboxes the 101.

What generics cannot do: new T() and new T[]#

Why does Bin use an ArrayList<T>? Here is a plain-array version, plus a spare item from T’s constructor:

LostAndFound.java
class Bin<T> {
    private T[] items = new T[10];
    private T spare = new T();
}

public class LostAndFound {
    public static void main(String[] args) {
        Bin<String> scarves = new Bin<>();
    }
}
LostAndFound.java:2: error: generic array creation
    private T[] items = new T[10];
                        ^
LostAndFound.java:3: error: unexpected type
    private T spare = new T();
                          ^
  required: class
  found:    type parameter T
  where T is a type-variable:
    T extends Object declared in class Bin
2 errors

Neither line compiles, for one shared reason. Java checks generic types while compiling and then removes them, so the running program no longer knows what T was. This is called type erasure. Creating an object or an array needs the real class, and after erasure there is none. (And T might not even have a no-argument constructor.)

So store many Ts in an ArrayList<T>. The library’s ArrayList<E> meets the same limit from the inside. It keeps its elements in a plain Object[]. When you call get, the compiler quietly adds the cast to your code, so you never write it.

Type this one yourself

Do not paste this one: typing it is how the two positions of <T> stick. Add a static method binOf(String label, T[] shelf) that returns a new Bin holding every item on the shelf. Test it with items and tags.

Show the answer

The method is generic, so <T> goes before the return type. The return type is a generic class, so T appears twice in a row:

public static <T> Bin<T> binOf(String label, T[] shelf) {
    Bin<T> bin = new Bin<>(label);
    for (T item : shelf) {
        bin.add(item);
    }
    return bin;
}
Desk [umbrella, scarf, keys]
Tags [104, 101, 103]

Inference made T a String, then an Integer, so each bin came back already labeled.

What was new in this guide#

  1. A type parameter <T> is a blank that a type argument fills in.
  2. An Object version needs casts that can fail at run time.
  3. A generic method puts <T> before its return type.
  4. Type inference finds T from argument types and the target type, never values.
  5. A bound such as <T extends Number> limits the types and unlocks their methods.
  6. A generic class puts <T> after its name; the diamond <> infers it.
  7. Type arguments are reference types, and T values are compared with equals.
  8. Type erasure rules out new T() and new T[n].
One sentence to carry into the exam

<T> is a blank type that the user fills in and the compiler checks. It goes before the return type of a generic method and after the name of a generic class. Add extends to limit the allowed types so you can call their methods. Type arguments are reference types, so write Integer, never int.

Where these go wrong#

  • Forgetting <T> before the return type of a generic method. The compiler looks for a class called T and reports cannot find symbol.
  • Repeating <T> on a method inside a generic class. public <T> void add(T item) inside Bin<T> declares a second, unrelated T. Then items.add(item) fails with T#1 cannot be converted to T#2.
  • Using a primitive as the type argument. Bin<int> fails; use Bin<Integer>.
  • Passing an int[] to a method that takes T[]. T cannot be int, so use an Integer[].
  • Calling compareTo on a plain T. A plain T only has Object’s methods. Bound it: <T extends Comparable<T>>.
  • Writing implements in a bound. Bounds always use extends.
  • Comparing T values with ==. It asks “same object?”, and for Integers above 127 the answer depends on the JVM. Use equals.
  • Leaving the angle brackets off: new Bin("Scarves"). That is a raw type, a Bin with no label, so the compiler cannot check it. Write new Bin<>("Scarves").
  • Writing new T() or new T[n]. Neither compiles because of type erasure; use an ArrayList<T>.

On the exam: “write a generic method” means only the method, and marks are often lost on a missing <T> before the return type. For “write a generic class”, <T> goes after the class name only. Read the question twice, answer, then reread to check you did every part.

Practice#

Answer each one on paper before you look at the solutions. Every answer that involves running code was checked by compiling and running it.

  1. In public static <T> T first(T[] arr), what does each of the three Ts mean?
  2. Write a generic method countMatches(T[] items, T target) that returns how many items equal target. Test it on Strings and Integers.
  3. Why does this not compile, and how do you fix it?
    public static <T> T bigger(T a, T b) {
        if (a.compareTo(b) > 0) return a;
        return b;
    }
  4. Write a generic class Box<T> with a constructor, get, set and isEmpty (true when the contents are null).
  5. Write a bounded generic method that returns the smallest element of an array, and show it working on Integers and Strings.
  6. Which of these compile? Pair<String, Integer> a = new Pair<>("x", 1);   Pair<String, int> b;   Stats<String> c; where class Stats<T extends Number>.

Solutions#

  1. The first, inside <T>, declares the type parameter. The second is the return type: the method returns a T. The third says the parameter is an array of T. When called with a String[], all three become String.
  2. Use equals, which every object has, so no bound is needed:
    public class QCount {
        public static <T> int countMatches(T[] items, T target) {
            int count = 0;
            for (T item : items) {
                if (item.equals(target)) {
                    count++;
                }
            }
            return count;
        }
    
        public static void main(String[] args) {
            String[] votes = {"yes", "no", "yes", "yes"};
            Integer[] dice = {6, 2, 6};
            System.out.println(countMatches(votes, "yes"));
            System.out.println(countMatches(dice, 6));
        }
    }
    3
    2
  3. A plain T might be any type, and not every type has compareTo, so the compiler reports cannot find symbol. Add a bound so only comparable types are allowed: public static <T extends Comparable<T>> T bigger(T a, T b).
  4. Every place that would have said a specific type says T instead:
    class Box<T> {
        private T contents;
    
        public Box(T contents) {
            this.contents = contents;
        }
    
        public T get() {
            return contents;
        }
    
        public void set(T contents) {
            this.contents = contents;
        }
    
        public boolean isEmpty() {
            return contents == null;
        }
    }
    
    public class QBox {
        public static void main(String[] args) {
            Box<String> b = new Box<>("socks");
            System.out.println(b.get() + " " + b.isEmpty());
            b.set(null);
            System.out.println(b.isEmpty());
        }
    }
    socks false
    true
  5. Bound T to Comparable<T> so compareTo is allowed:
    public class QMin {
        public static <T extends Comparable<T>> T smallest(T[] items) {
            T min = items[0];
            for (T item : items) {
                if (item.compareTo(min) < 0) {
                    min = item;
                }
            }
            return min;
        }
    
        public static void main(String[] args) {
            Integer[] n = {8, 3, 9};
            String[] s = {"kiwi", "fig", "lime"};
            System.out.println(smallest(n));
            System.out.println(smallest(s));
        }
    }
    3
    fig
  6. Only the first. int is a primitive and cannot be a type argument, and String is not a Number, so it is outside the bound of Stats.

Test-readiness checklist#

These are the items from the course’s Exam 2 topic list that this guide covers. Tick each one only when you can do it without looking.

  • ☐  I can explain what generics are and why they catch errors at compile time.
  • ☐  I can write and call generic methods, with the type parameter before the return type.
  • ☐  I can write bounded generics with extends and explain what the bound allows.
  • ☐  I can write and use generic classes with one or more type parameters.

Test yourself in the free Kestrel Exams app

40 practice questions on generic methods, generic classes and bounds, with every code answer checked by compiling and running it. Free, offline, no account.

Practise generics →

Frequently asked questions#

What are generics in Java?

Generics let a class or method be written with a type parameter, usually T, that is filled in with a real type when the class or method is used. The compiler then checks every use against that type, catching mistakes at compile time and removing the need for casts.

How do you write a generic method in Java?

Declare the type parameter in angle brackets just before the return type, then use it like any type: public static <T> void printAll(T[] items). Callers do not usually name the type; Java infers it from the arguments.

What is a bounded generic type?

A type parameter limited to a class or interface and its subtypes, written with extends, for example <T extends Number> or <T extends Comparable<T>>. The bound restricts which types may be used and in return lets the code call that type's methods, such as doubleValue() or compareTo().

How do you write a generic class in Java?

Put the type parameters after the class name, as in class Pair<A, B>, and use A and B as the types of fields, parameters and return values. Create objects with the types filled in: new Pair<String, Integer>("Ana", 20), or new Pair<>("Ana", 20) using the diamond operator.

Why can I not use int with generics?

Type arguments must be reference types, and int is a primitive. Use the wrapper class Integer instead; Java converts between int and Integer automatically through autoboxing.

Why can I not create a generic array with new T[]?

Because of type erasure: Java checks generic types at compile time and then removes them, so at run time it does not know what T is and cannot create an array of that exact type. Use an ArrayList<T> instead.

Suggest a change

Something here not clear? A topic you wish we covered? Tell us. We read every message, and a request is the fastest way to get a guide written — several of these exist because somebody asked.