python-scala-idioms
Guide for writing idiomatic Scala when translating from Python
Install / Use
npx skills add benchflow-ai/skillsbench --skill python-scala-idiomsInstalls into whichever agent you are using.
SKILL.md
Installable skill definition
Quality Score
Category
Content & MediaSupported Platforms
Our assessment of python-scala-idioms
python-scala-idioms scores 89/100 on our quality scale, 470th of 1,209 Content & Media skills we index (top 39%).
Its SKILL.md is 7.3 KB long, well organised into 24 sections with 21 code examples: a thorough specification that gives an agent plenty to work with.
With 1,813 GitHub stars, it is one of the more widely adopted skills in the catalogue.
Maintenance, license and trust
- The repository was last updated about 2 months ago, so python-scala-idioms is actively maintained.
- It is released under the Apache-2.0 license, a permissive license that allows use, modification and commercial use with attribution.
- Its trust signals score 100/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
python-scala-idioms compared with similar skills
All 4 of these similar skills score higher than python-scala-idioms; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| python-scala-idioms (this skill)by benchflow-ai | 89 | 1.8k | 2mo ago | SKILL.md |
| Agent-Reachby Panniantong | 100 | 90.5k | 19d ago | CLAUDE.md |
| headroomby headroomlabs-ai | 100 | 74.4k | 1d ago | CLAUDE.md |
| Scraplingby D4Vinci | 100 | 85.6k | today | MCP Server |
| crawl4aiby unclecode | 100 | 84.8k | 9d ago | MCP Server |
Frequently asked questions
- How do I install python-scala-idioms?
- Run
npx skills add benchflow-ai/skillsbench --skill python-scala-idioms. The install tabs above show the steps for each supported agent. - Which AI agents does python-scala-idioms work with?
- It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
- Is python-scala-idioms safe to use?
- It is Apache-2.0-licensed and scores 100/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is python-scala-idioms still maintained?
- The repository was last updated about 2 months ago, so python-scala-idioms is actively maintained.
Skill content
View source on GitHubname: python-scala-idioms description: 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.
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", "alice@example.com", 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", "alice@example.com", 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", "alice@example.com", 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)(_ + _)
Related Skills
Agent-Reach
90.5kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
headroom
74.4kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
Scrapling
85.6k🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scrapling_dev
crawl4ai
84.8kOpen-source web crawler and scraper for LLMs and AI agents: any website into clean, LLM-ready Markdown. Run it yourself, or use Crawl4AI Cloud with one key.
Languages
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
