Why value method cannot be used outside macros?

走远了吗. 提交于 2021-02-08 09:37:12

问题


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):

  1. All your Scala build code is run.
  2. It contains some settings and tasks definitions, SBT collects those when it encounters (along with ones from core, plugins, etc.)
  3. They are topologically sorted into the task graph, deduplicated ("the last one to execute wins"), etc.
  4. Settings are evaluated.
  5. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!