agentsclimarketplace

Run2 scala variance

Skill cxcscmu/SkillLearnBench/skills/b2-self-feedback-claude-sonnet-4-6/python-scala-translation/run2_scala-variance

Translating Python TypeVar covariant/contravariant generics to Scala variance annotations, with concrete patterns for containers, sinks, and handlers.From its SKILL.md

Install
npx -y skills add cxcscmu/SkillLearnBench --skill run2_scala-variance

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

SKILL.md

3.6 KB, 933 tokens by cl100k_base, as published. Nobody here has run it

Scala Variance Annotations (vs Python TypeVars)

Python TypeVar → Scala Variance

T_co    = TypeVar("T_co",    covariant=True)     # +T in Scala
T_contra = TypeVar("T_contra", contravariant=True) # -T in Scala
T       = TypeVar("T")                            # T  in Scala (invariant)

Variance Rules

AnnotationMeaningT can appear inSubtyping
+TCovariantOutput (return types)F[Dog] <: F[Animal]
-TContravariantInput (parameters)F[Animal] <: F[Dog]
TInvariant (default)BothNo subtype relation

Common Variance Problem: Covariant T in Function Parameter Position

Python doesn't enforce variance rules, but Scala does at compile time:

# Python allows this — T_co (covariant) used in contravariant (input) position
class TokenContainer(Generic[T_co]):
    def map_tokens(self, func: Callable[[T_co], str]) -> list[str]: ...

Scala compiler REJECTS:

class TokenContainer[+T] {
  def mapTokens(f: T => String): List[String]  // ERROR: covariant T in contravariant position
}

Scala fix — use a lower bound:

class TokenContainer[+T](items: Seq[T]) {
  def mapTokens[B >: T](f: B => String): List[String] = items.map(f).toList
  // B >: T: B is a supertype of T. f accepts B, and T values can be passed as B.
}

Covariant Container (read-only)

final class TokenContainer[+T](items: Seq[T]) {
  private val _items: Vector[T] = items.toVector
  def getAll: Vector[T]         = _items
  def size: Int                 = _items.size
  def mapTokens[B >: T](f: B => String): List[String] = _items.map(f).toList
}
  • Vector[T] is itself covariant, so returning it from +T class is fine.
  • getAll returns Vector[T] — covariant position ✓

Contravariant Sink (write-only)

final class TokenSink[-T] {
  private var _received: List[Any] = Nil   // List[Any] avoids variance issue in var
  def receive(item: T): Unit = _received = _received :+ (item: Any)
  def drain(): List[Any] = {
    val result = _received
    _received = Nil
    result
  }
}
  • List[Any] instead of List[T] — a var List[T] with -T would be invalid
  • receive(item: T) — contravariant position ✓

Invariant Handler (read + write)

final class BivariantHandler[T](private var value: T) {
  def get: T               = value
  def set(v: T): Unit      = value = v
  def transform(f: T => T): T = { value = f(value); value }
}
  • Both get (output) and set (input) use T → must be invariant

Abstract Generic Tokenizer

abstract class BaseTokenizer[T] {
  def tokenize(value: T): Token                              // abstract
  def tokenizeBatch(values: Iterable[T]): Iterator[Token] = // concrete default
    values.iterator.map(tokenize)
}
  • Iterable[T] is covariant, so tokenizeBatch works correctly.
  • Concrete subclasses implement tokenize.

Concrete Subclass Pattern

final class StringTokenizer(
  encoding: String = "UTF-8",
  normalizer: String => String = identity
) extends BaseTokenizer[String] {
  def tokenize(value: String): Token = Token(normalizer(value), TokenType.STRING)
  def tokenizeBytes(bytes: Array[Byte]): Token = tokenize(new String(bytes, encoding))
}

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.