python-scala-idioms
Helps developers write idiomatic, functional Scala code when migrating from Python.
Install
mkdir -p .claude/skills/python-scala-idioms && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/5767" && unzip -o skill.zip -d .claude/skills/python-scala-idioms && rm skill.zipInstalls to .claude/skills/python-scala-idioms
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Guide for writing idiomatic Scala when translating from Python. Use when the goal is not just syntactic translation but producing clean, idiomatic Scala code. Covers immutability, expression-based style, sealed hierarchies, and common Scala conventions.Key capabilities
- →Convert mutable Python classes to immutable Scala case classes
- →Replace null checks with Option, Either, or Try types
- →Translate procedural if-else chains into expression-based pattern matching
- →Refactor Python loops into functional collection methods like map and filter
- →Apply Scala naming conventions for variables and constants
How it works
The skill provides a set of transformation patterns that map common Python procedural constructs to Scala's functional and type-safe paradigms.
Inputs & outputs
When to use python-scala-idioms
- →Convert Python list comprehensions to Scala maps
- →Rewrite Python classes as Scala case classes
- →Refactor procedural code to functional Scala
About this skill
Python to Idiomatic Scala Translation
Core Principles
When translating Python to Scala, aim for idiomatic Scala, not literal translation:
- Prefer immutability - Use
valovervar, immutable collections - Expression-based - Everything returns a value, minimize statements
- Type safety - Leverage Scala's type system, avoid
Any - Pattern matching - Use instead of if-else chains
- Avoid null - Use
Option,Either,Try
Immutability First
# Python - mutable by default
class Counter:
def __init__(self):
self.count = 0
def increment(self):
self.count += 1
return self.count
// Scala - immutable approach
case class Counter(count: Int = 0) {
def increment: Counter = copy(count = count + 1)
}
// Usage
val c1 = Counter()
val c2 = c1.increment // Counter(1)
val c3 = c2.increment // Counter(2)
// c1 is still Counter(0)
Expression-Based Style
# Python - statement-based
def get_status(code):
if code == 200:
status = "OK"
elif code == 404:
status = "Not Found"
else:
status = "Unknown"
return status
// Scala - expression-based
def getStatus(code: Int): String = code match {
case 200 => "OK"
case 404 => "Not Found"
case _ => "Unknown"
}
// No intermediate variable, match is an expression
Sealed Hierarchies for Domain Modeling
# Python - loose typing
def process_payment(method: str, amount: float):
if method == "credit":
# process credit
pass
elif method == "debit":
# process debit
pass
elif method == "crypto":
# process crypto
pass
// Scala - sealed trait for exhaustive matching
sealed trait PaymentMethod
case class CreditCard(number: String, expiry: String) extends PaymentMethod
case class DebitCard(number: String) extends PaymentMethod
case class Crypto(walletAddress: String) extends PaymentMethod
def processPayment(method: PaymentMethod, amount: Double): Unit = method match {
case CreditCard(num, exp) => // process credit
case DebitCard(num) => // process debit
case Crypto(addr) => // process crypto
}
// Compiler warns if you miss a case!
Replace Null Checks with Option
# Python
def find_user(id):
user = db.get(id)
if user is None:
return None
profile = user.get("profile")
if profile is None:
return None
return profile.get("email")
// Scala - Option chaining
def findUser(id: Int): Option[String] = for {
user <- db.get(id)
profile <- user.profile
email <- profile.email
} yield email
// Or with flatMap
def findUser(id: Int): Option[String] =
db.get(id)
.flatMap(_.profile)
.flatMap(_.email)
Prefer Methods on Collections
# Python
result = []
for item in items:
if item.active:
result.append(item.value * 2)
// Scala - use collection methods
val result = items
.filter(_.active)
.map(_.value * 2)
Avoid Side Effects in Expressions
# Python
items = []
for x in range(10):
items.append(x * 2)
print(f"Added {x * 2}")
// Scala - separate side effects
val items = (0 until 10).map(_ * 2).toList
items.foreach(x => println(s"Value: $x"))
// Or use tap for debugging
val items = (0 until 10)
.map(_ * 2)
.tapEach(x => println(s"Value: $x"))
.toList
Use Named Parameters for Clarity
# Python
def create_user(name, email, admin=False, active=True):
pass
user = create_user("Alice", "[email protected]", admin=True)
// Scala - named parameters work the same
def createUser(
name: String,
email: String,
admin: Boolean = false,
active: Boolean = true
): User = ???
val user = createUser("Alice", "[email protected]", admin = true)
// Case class with defaults is often better
case class User(
name: String,
email: String,
admin: Boolean = false,
active: Boolean = true
)
val user = User("Alice", "[email protected]", admin = true)
Scala Naming Conventions
| Python | Scala |
|---|---|
snake_case (variables, functions) | camelCase |
SCREAMING_SNAKE (constants) | CamelCase or PascalCase |
PascalCase (classes) | PascalCase |
_private | private keyword |
__very_private | private[this] |
# Python
MAX_RETRY_COUNT = 3
def calculate_total_price(items):
pass
class ShoppingCart:
def __init__(self):
self._items = []
// Scala
val MaxRetryCount = 3 // or final val MAX_RETRY_COUNT
def calculateTotalPrice(items: List[Item]): Double = ???
class ShoppingCart {
private var items: List[Item] = Nil
}
Avoid Returning Unit
# Python - None return is common
def save_user(user):
db.save(user)
# implicit None return
// Scala - consider returning useful information
def saveUser(user: User): Either[Error, UserId] = {
db.save(user) match {
case Right(id) => Right(id)
case Left(err) => Left(err)
}
}
// Or at minimum, use Try
def saveUser(user: User): Try[Unit] = Try {
db.save(user)
}
Use Apply for Factory Methods
# Python
class Parser:
def __init__(self, config):
self.config = config
@classmethod
def default(cls):
return cls(Config())
// Scala - companion object with apply
class Parser(config: Config)
object Parser {
def apply(config: Config): Parser = new Parser(config)
def apply(): Parser = new Parser(Config())
}
// Usage
val parser = Parser() // Calls apply()
val parser = Parser(customConfig)
Cheat Sheet: Common Transformations
| Python Pattern | Idiomatic Scala |
|---|---|
if x is None | x.isEmpty or pattern match |
if x is not None | x.isDefined or x.nonEmpty |
x if x else default | x.getOrElse(default) |
[x for x in xs if p(x)] | xs.filter(p) |
[f(x) for x in xs] | xs.map(f) |
any(p(x) for x in xs) | xs.exists(p) |
all(p(x) for x in xs) | xs.forall(p) |
next(x for x in xs if p(x), None) | xs.find(p) |
dict(zip(keys, values)) | keys.zip(values).toMap |
isinstance(x, Type) | x.isInstanceOf[Type] or pattern match |
try: ... except: ... | Try { ... } or pattern match |
| Mutable accumulator loop | foldLeft / foldRight |
for i, x in enumerate(xs) | xs.zipWithIndex |
Anti-Patterns to Avoid
// DON'T: Use null
val name: String = null // Bad!
// DO: Use Option
val name: Option[String] = None
// DON'T: Use Any or type casts
val data: Any = getData()
val name = data.asInstanceOf[String]
// DO: Use proper types and pattern matching
sealed trait Data
case class UserData(name: String) extends Data
val data: Data = getData()
data match {
case UserData(name) => // use name
}
// DON'T: Nested if-else chains
if (x == 1) ... else if (x == 2) ... else if (x == 3) ...
// DO: Pattern matching
x match {
case 1 => ...
case 2 => ...
case 3 => ...
}
// DON'T: var with mutation
var total = 0
for (x <- items) total += x
// DO: fold
val total = items.sum
// or
val total = items.foldLeft(0)(_ + _)
When not to use it
- →When the project requires literal syntactic translation rather than idiomatic Scala
- →When performance constraints strictly forbid the overhead of functional abstractions
Limitations
- →Does not automate full codebase migration
- →Requires manual verification of type safety and logic
How it compares
Unlike a direct syntax-to-syntax translator, this skill enforces Scala-specific idioms like immutability and exhaustive pattern matching.
Compared to similar skills
python-scala-idioms side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| python-scala-idioms (this skill) | 1 | 6mo | No flags | Intermediate |
| software-architecture | 333 | 6mo | No flags | Intermediate |
| effective-go | 323 | 9mo | No flags | Beginner |
| solid-principles | 57 | 9mo | No flags | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by benchflow-ai
View all by benchflow-ai →You might also like
software-architecture
davila7
Guide for quality focused software architecture. This skill should be used when users want to write code, design architecture, analyze code, in any case that relates to software development.
effective-go
openshift
Apply Go best practices, idioms, and conventions from golang.org/doc/effective_go. Use when writing, reviewing, or refactoring Go code to ensure idiomatic, clean, and efficient implementations.
solid-principles
SmidigStorm
Enforce SOLID principles (Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion) in object-oriented design. Use when writing or reviewing classes and modules.
typescript-review
metabase
Review TypeScript and JavaScript code changes for compliance with Metabase coding standards, style violations, and code quality issues. Use when reviewing pull requests or diffs containing TypeScript/JavaScript code.
react-modernization
wshobson
Upgrade React applications to latest versions, migrate from class components to hooks, and adopt concurrent features. Use when modernizing React codebases, migrating to React Hooks, or upgrading to latest React versions.
ast-grep
ast-grep
Guide for writing ast-grep rules to perform structural code search and analysis. Use when users need to search codebases using Abstract Syntax Tree (AST) patterns, find specific code structures, or perform complex code queries that go beyond simple text search. This skill should be used when users ask to search for code patterns, find specific language constructs, or locate code with particular structural characteristics.