Scala Generics and Type System for Python Developers

SkillDev tools

Translating Python generic types, variance, and type bounds to Scala 2.13

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Scala Generics and Type System for Python Developers skill

What this skill tells your AI

The instructions your AI receives, as published by cxcscmu/skilllearnbench in skills/b1-one-shot-claude-haiku-4-5/python-scala-translation/scala-generics/SKILL.md and read by ahel’s review.

Core Concepts

Variance (Key Difference from Python)

Python has no explicit variance system. Scala requires explicit declarations:

Covariance (+T) - "out" position, can return subtypes:

class Container[+T](items: Seq[T]) {
  def get: T = items.head  // OK - returning subtype
  // def set(t: T): Unit   // ERROR - would be contravariant
}

Contravariance (-T) - "in" position, can accept supertypes:

class Consumer[-T] {
  def consume(t: T): Unit  // OK - accepting supertype
  // def produce: T         // ERROR - would be covariant
}

Invariance (T) - exact type, no variance:

class Handler[T] {
  def get: T
  def set(t: T): Unit  // Both OK - invariant
}

Translation Pattern

PythonScalaNotes
TypeVar("T")[T]Invariant by default
TypeVar("T_co", covariant=True)[+T]Covariant, out-position only
TypeVar("T_contra", contravariant=True)[-T]Contravariant, in-position only
TypeVar("T", int, float)[T <: Int | Float]Upper bound (Scala 3) or sealed trait
Generic[T][T]Class definition
Union[A, B]A | B (Scala 3) or sealed traitUse sealed traits for compatibility

Type Bounds

// Upper bound - T must be subtype of Ordered
class Comparable[T <: Ordered[T]]

// Lower bound - T must be supertype of String
class Container[T >: String]

// Context bound (implicit evidence)
class Serializable[T: Format]

Higher-Kinded Types (Scala's advantage)

Python's TypeVar("F") for type constructors cannot express true HKTs. Scala can use type lambdas:

// Scala 2.13 with kind-projector
type Functor[F[_]] = {
  def map[A, B](fa: F[A], f: A => B): F[B]
}

// Or in Scala 3
def map[F[_], A, B](fa: F[A], f: A => B): F[B]

Translation Examples

Generic Container (Python)

class TokenContainer(Generic[T_co]):
    def __init__(self, items: Sequence[T_co]) -> None:
        self._items: tuple[T_co, ...] = tuple(items)

    def get_all(self) -> tuple[T_co, ...]:
        return self._items

Generic Container (Scala 2.13)

class TokenContainer[+T](items: Seq[T]) {
  private val _items: Vector[T] = items.toVector

  def getAll: Vector[T] = _items
  def size: Int = _items.size
}

Collections Generics

Python uses Sequence[T], Iterable[T], etc. Scala equivalents:

PythonScala
Sequence[T]Seq[T] (immutable)
Iterable[T]Iterable[T]
Iterator[T]Iterator[T]
list[T]scala.collection.mutable.ListBuffer[T] or List[T] (immutable)
tuple[T, ...]Vector[T] or (T, T, ...) for fixed size
dict[K, V]Map[K, V]

Best Practices for Scala 2.13

  1. Prefer immutable by default - use Vector, List, Map
  2. Generics in method position - use [T] not just at class level
  3. Variance where appropriate - adds flexibility but keep simple
  4. Use sealed traits for union types - more powerful than Python's Union
  5. Type classes for ad-hoc polymorphism - replaces duck typing

Working with Circe JSON Types

Circe provides Json type which is immutable and generic:

import io.circe._

// Json is essentially: Json = JNull | JBoolean | JNumber | JString | JArray | JObject
val json: Json = Json.fromString("hello")
val jsonObj: Json = Json.obj("key" -> Json.fromString("value"))

Signals

GitHub stars
83
Forks
5
Last commit
Jul 2026
Advanced
Catalog kind
skill
Gateway key
scala-generics
Source
github.com/cxcscmu/skilllearnbench