Skip to content

Commit a518ac6

Browse files
update README
1 parent 955a4e2 commit a518ac6

File tree

1 file changed

+46
-9
lines changed

1 file changed

+46
-9
lines changed

README.md

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,13 @@ This project provides Java annotations that enable fine-grained specification of
1717
- [Background](#background)
1818
- [What is variance](#what-is-variance)
1919
- [Types of variance](#types-of-variance)
20+
- [New variance notions introduced in this project](#new-variance-notions-introduced-in-this-project)
21+
- [Depth](#depth)
22+
- [Side Variance](#side-variance)
23+
- [Specifying subtyping relationships with required types](#specifying-subtyping-relationships-with-required-types)
2024
- [Usage](#usage)
2125
- [Annotations](#annotations)
22-
- [Output](#output)
26+
- [Building and running your project](#building-and-running-your-project)
2327
- [Contributing](#contributing)
2428

2529
## Installation
@@ -113,7 +117,7 @@ If we define a depth of 2:
113117

114118
For example, consider the following type hierarchy:
115119

116-
`Animal` ── `Mammal` ── `Dog`
120+
`Animal` ── `Mammal` ── `Dog`
117121

118122
If we define a depth of 1:
119123

@@ -128,11 +132,42 @@ For example, onsider the types `Animal`, `Dog`, and `Cat`, where `Dog` and `Cat`
128132
- `List<Dog>` would be a subtype of `List<Cat>`.
129133
- Similarly, `List<Cat>` would be a subtype of `List<Dog>`.
130134

135+
#### Specifying subtyping relationships with required types
136+
137+
By specifying a list of type names, you can enforce that any subtype must relate to all of the provided types. Here, the concept of "relate" means that the subtype must either be a **subtype** or a **supertype** of the specified types.
138+
139+
**Required Subtypes**
140+
You can supply a list of required subtypes, meaning all types in the list must be subtypes of the given type for it to qualify as a valid subtype.
141+
142+
**Required Supertypes**
143+
Conversely, for required supertypes, the given type must be a supertype of all the specified types to be considered valid.
144+
145+
This allows for control over the branching points in your type hierarchy.
146+
147+
To illustrate with an example, consider the following type hierarchy:
148+
149+
`Animal` ── `Mammal` ── `Dog`
150+
151+
└── `Bird` ── `Parrot`
152+
153+
If you specify a list to be **covariant** with the required subtypes as `[Dog]`, then:
154+
155+
- **`List<Mammal>`** would be a valid subtype of **`List<Animal>`**, because `Dog` is a subtype of `Mammal`.
156+
- **`List<Bird>`**, however, would **not** be a valid subtype of **`List<Animal>`**, since `Dog` is not a subtype of `Bird`.
157+
131158
## Usage
132159

133-
To specify variance for classes, annotate the relevant type parameters with one of the provided annotations (details on these annotations will follow). Once annotated, you can use your classes as though they conform to the specified variance. Note that your IDE's linter may flag errors if the classes are used in ways that Java does not natively support. These warnings are expected and can be safely ignored.
160+
### How it works
161+
162+
To specify variance for your classes, annotate the relevant type parameters with one of the provided annotations (details on these annotations will follow). After annotating, you can use your classes as if they conform to the specified variance. However, note that your IDE’s linter may flag errors when using these classes in ways that Java does not natively support. These warnings are expected and can be safely ignored.
163+
164+
The reason these warnings can be ignored lies in how Java's generics work. Generics in Java are essentially syntactic sugar-they are erased at compile-time. The compiler erases all generic types and replaces them with type casts to ensure type safety. This same technique is applied here.
165+
166+
When projects using these annotations are compiled, an annotation processor runs. This processor analyzes the source files, parsing them into Abstract Syntax Trees (ASTs), and erases any instances of variant class arguments by replacing them with their leftmost bound. Later, when the argument is output, the processor inserts a cast back to the type it was originally marked as. This allows us to avoid type-related errors because every instance of the class will be of the exact same type.
167+
168+
While this method may seem risky, as it removes type safety and could potentially lead to crashes, the annotation processor ensures type safety is preserved. The processor checks the ASTs to make sure that the types are correctly validated and do not cause issues during runtime.
134169

135-
When you compile the project, a new output directory named `output_javavariance` will be created. In this directory, type arguments are erased, and the necessary casts are inserted to ensure the project runs correctly. At this stage, any previously flagged errors should no longer appear.
170+
When you compile your project, a new output directory named `output_javavariance` is created. In this directory, type arguments are erased, and the necessary casts are inserted to ensure the project runs correctly. At this stage, any previously flagged errors should no longer appear, and the project should function as expected.
136171

137172
### Annotations
138173

@@ -142,11 +177,13 @@ There are currently three annotations provided by this project: `MyVariance`, `C
142177

143178
MyVariance is the most customizable one, and allows you to experiment with different types of variance. There are several parameters you can provide to specify what variance rules should apply:
144179

145-
| Parameter | Description | Possible values |
146-
| ---------- | ------------------------------------------------------------- | ----------------------------------------------------------- |
147-
| `variance` | Specifies which variance type to use | COVARIANT, CONTRAVARIANT, INVARIANT, BIVARIANT, SIDEVARIANT |
148-
| `depth` | How deep subtyping goes | Integer value ≥ 0 |
149-
| `strict` | Whether compilation should fail if any errors are encountered | `true`, `false` |
180+
| Parameter | Description | Possible values |
181+
| -------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
182+
| `variance` | Specifies which variance type to use | COVARIANT, CONTRAVARIANT, INVARIANT, BIVARIANT, SIDEVARIANT |
183+
| `depth` | How deep subtyping goes | Integer value ≥ 0 |
184+
| `strict` | Whether compilation should fail if any errors are encountered | `true`, `false` |
185+
| `requiredSubtypes` | A list of types that must be a subtype of any given type for it to be considered valid | Any primitive array of strings |
186+
| `requiredSupertypes` | A list of types that must be a supertype of any given type for it to be considered valid | Any primitive array of strings |
150187

151188
#### Covariant
152189

0 commit comments

Comments
 (0)