-
Notifications
You must be signed in to change notification settings - Fork 935
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Settings should use dynamic dispatch semantics #2899
Comments
Your expectation doesn't match mine in terms of |
That's because you know the implementation details of Would you accept my expection if I used: baseDir in ThisBuild := file("/")
srcDir in ThisBuild := baseDir.value / "src" or What I'm trying to define is a default definition for With regards to categorization, I've learnt it's very hard to define things (bug, feature requests, workarounds, hacks, api usages, etc) - one man's bug is another man's feature request. I personally feel that this is a bug, one which lots of sbt users and developers have suffered through, typically by throwing things at walls and giving up completely on scopes (ie. using commonSettings over inThisBuild). |
Using the terminology that I defined in http://www.scala-sbt.org/0.13/docs/Basic-Def.html, we can break down
Let's just focus on key first. Key is You wrote:
That's where things get weird. We can't have one key that can "respond". |
When keys not defined in project-scope fall back to ThisBuild, then it is essentially inheritance. Only instead of being physical Scala code inheritance, it's inheritance done as values. To put it back into the code it's emulating: import java.io.File
trait ThisBuildSettings {
def baseDir: File = new File("/")
def srcDir: File = new File(baseDir, "src")
}
object ProjectA extends ThisBuildSettings {
override def baseDir: File = new File("/a")
}
object Main {
def main(args: Array[String]): Unit = {
println(s"ProjectA srcDir: ${ProjectA.srcDir}")
}
}
I know and understand what the workarounds to the bug are. |
related to #2534 |
Some details of |
Here's an example for the task axis, from the sbt/sbt gitter room:
|
I don’t really understand the use case. Shouldn’t a task do the same thing no matter how it is evaluated? If there is a different scalaVersion for compile and run, are we supposed to recompile the project when we invoke run after we’ve previously invoked compile? Adding some kind of dynamic dispatch where the current command sets the scope seems likely to create even more confusion about how a task or setting is defined. |
It's a different evaluation model than it is currently, but I think it's viable, yes. Modelled in Scala: trait HasCompile {
def sources: Seq[File]
def scalaVersion: String = "2.12.8"
def compile(): Seq[File] = Zinc.compile(sources, scalaVersion)
}
trait HasRun extends HasCompile {
override def scalaVersion: String = "2.13.0" // user override for `run`
def run(): Unit = {
val classfiles = compile()
Zinc.run(classfiles)
}
} |
I agree with the initial issue that it would be an improvement if settings were bound late so that you'd get /a/src instead of /src in the a project. My interpretation of the gitter discussion is that the user expects settings set at the task level to propagate to the task's delegates. I don't think that makes sense. Extending your trait HasScalaVersion {
def scalaVersion: String
}
trait HasCompile with HasScalaVersion {
override def scalaVersion: String = "2.12.8"
def sources: Seq[File]
def compile(): Seq[File] = Zinc.compile(sources, scalaVersion)
}
trait HasRun {
def run(): Unit
}
class Runner(val compiler: HasCompile) extends HasRun with HasScalaVersion {
override def scalaVersion: String = "2.13.0"
override def run(): Unit = Zinc.run(compiler.compile())
} and we expected Runner to generate |
Delegation and inheritance have different semantics and expectations. I think there is a fair argument to be made that sbt would be easier for many scala users if it used inheritance. Martin Odersky has more or less made that argument: https://docs.google.com/document/d/1QdtRJGxlKTiXcAxsjXWLtWVzeZyUzGVDh8oOYOiuhwg/edit. |
Doesn't my example use inheritance and yours use delegation? Anyways I'm less sure about task-level delegation than build/project level delegation. |
#5202 another case. |
is this still an issue if ThisBuild doesn't exist? (i think it shouldn't) |
Yes, I think so. Even at default definition level (i.e. // default definitions from sbt
Global / scalaVersion := "2.13.1"
Global / crossScalaVersions := Seq(scalaVersion)
// in your project
val foo = project.settings(
scalaVersion := "2.12.10" // this should propate to crossScalaVersions
) (Btw, that example works today due to "derived" settings, which is the hackaround to this issue, and problematic in its own way.) |
steps
problem
expectation
In
ThisBuild
scope,srcDir
is defined in terms ofbaseDir
.Later, in project
a
and projectb
, in project scopebaseDir
is redefined.Intuitively, imho,
a/*:srcDir
should be/a/src
not/src
.notes
sbt.version=0.13.13
Also, using taskKeys instead of settingKeys changes nothing.
The text was updated successfully, but these errors were encountered: