Sam Malayek
Sam Malayek

Reputation: 3755

What is the SBT := operator in build.sbt?

I'm new to Scala and SBT. I noticed an unfamiliar operator in the build.sbt of an open source project:

:=

Here are a couple examples of how it's used:

lazy val akkaApp = Project(id = "akka-app", base = file("akka-app"))
  .settings(description := "Common Akka application stack: metrics, tracing, logging, and more.")

and it's used a few times in this larger code snippet:

lazy val jobServer = Project(id = "job-server", base = file("job-server"))
  .settings(commonSettings)
  .settings(revolverSettings)
  .settings(assembly := null.asInstanceOf[File])
  .settings(
    description := "Spark as a Service: a RESTful job server for Apache Spark",
    libraryDependencies ++= sparkDeps ++ slickDeps ++ cassandraDeps ++ securityDeps ++ coreTestDeps,
    test in Test <<= (test in Test).dependsOn(packageBin in Compile in jobServerTestJar)
      .dependsOn(clean in Compile in jobServerTestJar)
      .dependsOn(buildPython in jobServerPython)
      .dependsOn(clean in Compile in jobServerPython),
    testOnly in Test <<= (testOnly in Test).dependsOn(packageBin in Compile in jobServerTestJar)
      .dependsOn(clean in Compile in jobServerTestJar)
      .dependsOn(buildPython in jobServerPython)
      .dependsOn(clean in Compile in jobServerPython),
    console in Compile <<= Defaults.consoleTask(fullClasspath in Compile, console in Compile),
    fullClasspath in Compile <<= (fullClasspath in Compile).map { classpath =>
      extraJarPaths ++ classpath
    },
    fork in Test := true
  )
  .settings(publishSettings)
  .dependsOn(akkaApp, jobServerApi)
  .disablePlugins(SbtScalariform)

My best guess is that it means "declare if not already declared".

Upvotes: 6

Views: 1654

Answers (1)

Andrey Tyukin
Andrey Tyukin

Reputation: 44918

The := has essentially nothing to do with the ordinary assignment operator =. It's not a built-in scala operator, but rather a family of methods/macros called :=. These methods (or macros) are members of classes such as SettingKey[T] (similarly for TaskKey[T] and InputKey[T]). They consume the right hand side of the key := value expression, and return instances of type Def.Setting[T] (or similarly, Tasks), where T is the type of the value represented by the key. They are usually written in infix notation. Without syntactic sugar, the invocations of these methods/macros would look as follows:

key.:=(value)

The constructed Settings and Tasks are in turn the basic building blocks of the build definition.

The important thing to understand here is that the keys on the left hand side are not some variables in a code block. Instead of merely representing a memory position in an active stack frame of a function call (as a simple variable would do), the keys on the left hand side are rather complex objects which can be inspected and passed around during the build process.

Upvotes: 7

Related Questions