Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


Simple smart constructor generation for Scala.

Copyright 2015 Dave Gurnell. Licensed Apache 2.

Build Status Coverage status Maven Central

Getting Started

Add the following to your build.sbt:

libraryDependencies += "com.davegurnell" %% "smartypants" % "<<VERSION>>"

You also need to add the Macro Paradise compiler plugin to your project (otherwise the @smart annotation won't do anything):

addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)


Smartypants provides a @smart macro to quickly define "smart constructors" for algebraic data types:

import smartypants._

sealed abstract class User extends Product with Serializable {
  def cookie: String

object User {
  @smart case class Anonymous(cookie: String) extends User
  @smart case class LoggedIn(email: String, cookie: String) extends User

val a = User.Anonymous("aCookie")
// a: User.Anonymous = Anonymous(aCookie)

val b = User.anonymous("aCookie")
// b: User = Anonymous(aCookie)

In this example, the @smart annotations define two constructor methods called anonymous and loggedIn. Each method takes the same number of parameters as its respective class and returns an instance of the class typed as a User.

The main use case for smart constructors is as a workaround for unhelpful type inference. For example:

implicit val userOrdering: Ordering[User] =

val users = List(User.Anonymous("cookie2"), User.Anonymous("cookie1"))
// users: List[User.Anonymous] = List(Anonymous(cookie2), Anonymous(cookie1))

val sorted = users.sorted
// <console>:17: error: No implicit Ordering defined for User.Anonymous.
//        users.sorted
//              ^

The problem here is that users is of type List[User.Anonymous], not List[User] as our ordering requires. We can fix this issue by inserting type annotations:

(users : List[User]).sorted

but our smart constructors let us bypass the problem altogether:

val users1 = List(User.anonymous("cookie2"), User.anonymous("cookie1"))
// users1: List[User] = List(Anonymous(cookie2), Anonymous(cookie1))

val sorted1 = users1.sorted
// sorted1: List[User] = List(Anonymous(cookie1), Anonymous(cookie2))

You can use @smart to annotate any inner class or object.


The @smart macro infers the name and type of the constructor from the annotated class or object:

// name is foo, return type is Bar
@smart case object Foo extends Bar

// name is baz, return type is Bar
@smart case class Baz(value: Int) extends Bar

You can customise the generated name by providing a value parameter:

@smart("alternativeName") case object Foo extends Bar

and the return type by providing a type parameter:

@smart[AnyRef] case class Baz(value: Int) extends Bar

You can even customise both at the same time:

@smart[AnyRef]("blah") case class Baz(value: Int) extends Bar

See the tests for more examples.


Simple smart constructor generation for Scala.






No releases published


No packages published