问题
The error message
`value` can only be used within a task or setting macro, such as :=, +=, ++=, Def.task, or Def.setting.
val x = version.value
^
clearly indicates how to fix the problem, for example, using :=
val x = settingKey[String]("")
x := version.value
The explanation in sbt uses macros heavily states
The
value
method itself is in fact a macro, one that if you invoke it outside of the context of another macro, will result in a compile time error, the exact error message being... And you can see why, since sbt settings are entirely declarative, you can’t access the value of a task from the key, it doesn’t make sense to do that.
however I am confused what is meant by declarative nature of sbt being the reason. For example, intuitively I would think the following vanilla Scala snippet is semantically similar to sbt's
def version: String = ???
lazy val x = s"Hello $version" // ok
trait Foo {
def version: String
val x = version // ok
}
As this is legal, clearly the Scala snippet is not semantically equivalent to the sbt one. I was wondering if someone could elaborate on why value
cannot be used outside macros? Is the reason purely syntactic related to macro syntax or am I missing something fundamental about sbt's nature?
回答1:
As another sentence there says
Defining sbt’s task engine is done by giving sbt a series of settings, each setting declaring a task implementation. sbt then executes those settings in order. Tasks can be declared multiple times by multiple settings, the last one to execute wins.
So at the moment when the line
val x = version.value
would be executed (if it were allowed!), that whole program is still being set up and SBT doesn't know the final definition of version
.
In what sense is the program "still being set up"?
SBT's order of actions is, basically (maybe missing something):
- All your Scala build code is run.
- It contains some settings and tasks definitions, SBT collects those when it encounters (along with ones from core, plugins, etc.)
- They are topologically sorted into the task graph, deduplicated ("the last one to execute wins"), etc.
- Settings are evaluated.
- Now you are allowed to actually run tasks (e.g. from SBT console).
version.value
is only available after step 4, but val x = version.value
runs on step 1.
Would not lazy evaluation take care of that?
Well, when you write val x = ...
there is no lazy evaluation. But lazy val x = ...
runs on step 1 too.
来源:https://stackoverflow.com/questions/61443657/why-value-method-cannot-be-used-outside-macros