With the following task declaration in project/Build.scala, the print task is not recognised when I type in print at an SBT console.
lazy val print = task { println("print") }
What's wrong?
You need a TaskKey for this to work that can be instantiated by using the taskKey macro:
lazy val printTask = taskKey[Unit]("print")
I recommend having a look at the corresponding documentation about tasks.
The documentation says:
The name of the val is used when referring to the task in Scala code. The string passed to the TaskKey method is used at runtime, such as at the command line
taskKey[Unit]("print") := println("print")
Then in your SBT console,
> print
print
In more complex code, you'll usually see keys separate from the settings.
val printTask = taskKey[Unit]("print")
printTask := println("print")
Related
I am reading SBT docs quite thoroughly now and there is a brief mention of Def.task and taskValue but there is no explanation so far.
They say here following:
You can compute values of some tasks or settings to define or append a value for another task.
It’s done by using Def.task and taskValue as an argument to :=, +=, or ++=.
And provide following code snippet:
sourceGenerators in Compile += Def.task {
myGenerator(baseDirectory.value, (managedClasspath in Compile).value)
}.taskValue
This brings more questions than answers for me. How is that different from regular dependency of some SBT task on another task? When should I use this macro? etc.
I have also tried to check scaladoc but without any success really. That part of code is not documented well.
I think this particular example in the introductory part of documentation is unnecessarily complicated. In this example you have to use .taskValue just because sourceGenerators value type is Seq[Task[Seq[File]]], so you have to add a task to it, not the value of that task.
A simpler example for that "Tasks based on other keys’ values" is
homepage := Some(
url(s"https://github.com/${organization.value}/${name.value}")
)
In the right part of :=/+=/++=/~= operators you can use other tasks values with simple .value suffix. Writing
foo := bar.value + 1
is the same as
foo := Def.task { bar.value + 1 }.value
In this simple example it's just unnecessary, but Def.task becomes useful when you want to separate task implementation from the task key setting:
def fooTask(n: Int): Def.Initialize[Task[Int]] = Def.task {
bar.value + n
}
So Def.task allows you to write a task definition and use other tasks/settings inside (with .value). Then you can evaluate this task definition when you set the corresponding task key somewhere else (in your project settings):
foo := fooTask(5).value
But if you need to refer to the task definition itself without evaluating it, you can use .taskValue instead of .value, like in your example. See documentation on generating sources for more information about sourceGenerators.
Here are some other relevant parts of the sbt documentation about tasks:
Tasks
Tasks/Settings: Motivation
Execution semantics of tasks
Sequencing tasks
What can I do within a file "example.jl" to exit/return from a call to include() in the command line
julia> include("example.jl")
without existing julia itself. quit() will just terminate julia itself.
Edit: For me this would be useful while interactively developing code, for example to include a test file and return from the execution to the julia prompt when a certain condition is met or do only compile the tests I am currently working on without reorganizing the code to much.
I'm not quite sure what you're looking to do, but it sounds like you might be better off writing your code as a function, and use a return to exit. You could even call the function in the include.
Kristoffer will not love it, but
stop(text="Stop.") = throw(StopException(text))
struct StopException{T}
S::T
end
function Base.showerror(io::IO, ex::StopException, bt; backtrace=true)
Base.with_output_color(get(io, :color, false) ? :green : :nothing, io) do io
showerror(io, ex.S)
end
end
will give a nice, less alarming message than just throwing an error.
julia> stop("Stopped. Reason: Converged.")
ERROR: "Stopped. Reason: Converged."
Source: https://discourse.julialang.org/t/a-julia-equivalent-to-rs-stop/36568/12
You have a latent need for a debugging workflow in Julia. If you use Revise.jl and Rebugger.jl you can do exactly what you are asking for.
You can put in a breakpoint and step into code that is in an included file.
If you include a file from the julia prompt that you want tracked by Revise.jl, you need to use includet(.
The keyboard shortcuts in Rebugger let you iterate and inspect variables and modify code and rerun it from within an included file with real values.
Revise lets you reload functions and modules without needing to restart a julia session to pick up the changes.
https://timholy.github.io/Rebugger.jl/stable/
https://timholy.github.io/Revise.jl/stable/
The combination is very powerful and is described deeply by Tim Holy.
https://www.youtube.com/watch?v=SU0SmQnnGys
https://youtu.be/KuM0AGaN09s?t=515
Note that there are some limitations with Revise, such as it doesn't reset global variables, so if you are using some global count or something, it won't reset it for the next run through or when you go back into it. Also it isn't great with runtests.jl and the Test package. So as you develop with Revise, when you are done, you move it into your runtests.jl.
Also the Juno IDE (Atom + uber-juno package) has good support for code inspection and running line by line and the debugging has gotten some good support lately. I've used Rebugger from the julia prompt more than from the Juno IDE.
Hope that helps.
#DanielArndt is right.
It's just create a dummy function in your include file and put all the code inside (except other functions and variable declaration part that will be place before). So you can use return where you wish. The variables that only are used in the local context can stay inside dummy function. Then it's just call the new function in the end.
Suppose that the previous code is:
function func1(...)
....
end
function func2(...)
....
end
var1 = valor1
var2 = valor2
localVar = valor3
1st code part
# I want exit here!
2nd code part
Your code will look like this:
var1 = valor1
var2 = valor2
function func1(...)
....
end
function func2(...)
....
end
function dummy()
localVar = valor3
1st code part
return # it's the last running line!
2nd code part
end
dummy()
Other possibility is placing the top variables inside a function with a global prefix.
function dummy()
global var1 = valor1
global var2 = valor2
...
end
That global variables can be used inside auxiliary function (static scope) and outside in the REPL
Another variant only declares the variables and its posterior use is free
function dummy()
global var1, var2
...
end
I'm using sbt v0.13.5
In my project, I'd like to have an sbt task that can accept some input (a single string), do some work on it and spit back some output (again, a single string). I've created a helper class in my project that does this that I can call from the terminal via sbt runMain (sbt "runMain com.example.utils.ClassName someArgument").
What I'd like is to save myself some typing and have an sbt task that does this. I'd like to just be able to type sbt doThing withStuff and have a taskKey named doThing that calls runMain with the name of the class to run and whatever argument was passed in.
I know how to create tasks but I can't seem to figure out how to call runMain from a custom task definition in my build.sbt. Can anyone point me in the correct direction?
TaskKey[Unit]("myTask") := (runMain in Compile).toTask(" com.example.Main arg1 arg2").value
runMain is an InputTask. InputTask has toTask method since 0.13.1.
https://github.com/sbt/sbt/commit/9dcb8727d819fb
https://github.com/sbt/sbt/blob/v0.13.6/main/settings/src/main/scala/sbt/InputTask.scala#L33
http://www.scala-sbt.org/0.13/docs/Input-Tasks.html#Get+a+Task+from+an+InputTask
If anybody wanted to run the main class with arguments computed basing on settings, you need dynamic tasks. For example:
val myRun = taskKey[Unit]("...")
myRun := Def.taskDyn {
val appName = name.value
Def.task {
(runMain in createApi in Compile)
.toTask(s" com.softwaremill.MyMain $appName")
.value
}
}.value
I'm interested in figuring out what some of the operations of sbt.TaskKey or sbt.SettingKey do
<<=
<+=
<++=
I know there are a lot of examples and docs in the document section of the main website, but I didn't find anything of help. Here's where I looked:
http://www.scala-sbt.org/release/docs/Getting-Started/More-About-Settings.html
http://www.scala-sbt.org/release/api/index.html#sbt.TaskKey
http://www.scala-sbt.org/release/api/index.html#sbt.SettingKey
sbt 0.12 syntax
If you want to learn about <<=-family of the operators, the best place to go is sbt 0.12.1 version of the Getting Started guide, specifically the page you linked More Kinds of Setting has a section called Computing a value based on other keys' values: <<=.
~= defines a new value in terms of a key's previously-associated value. But what if you want to define a value in terms of other keys' values?
<<= lets you compute a new value using the value(s) of arbitrary other keys.
<<= has one argument, of type Initialize[T]. An Initialize[T] instance is a computation which takes the values associated with a set of keys as input, and returns a value of type T based on those other values. It initializes a value of type T.
Given an Initialize[T], <<= returns a Setting[T], of course (just like :=, +=, ~=, etc.).
As noted in the document, <<= makes you think in terms of Initialize[T], so if you want to extract values out of multiple keys and compose it in some way, you'd need to do something like:
jarName in assembly <<= (name, version) map { (n, v) =>
n + "-assembly-" + v + ".jar" }
At this point you have to know somehow that jarName is a TaskKey not a SettingKey.
sbt 0.13 syntax
The reason you did not find <<= in the latest Getting Started guide, is that the sbt 0.13 syntax makes <<= obsolete. All you need is :=. sbt uses macro to expand the rhs of the := to generate the above out of this:
jarName in assembly := {
name.value + "-assembly-" + version.value + ".jar"
}
:= lets you think in T, so it's easier to deal with.
using let inline and member constraints I'll be able to make duck typing for known members but what if I would like to define a generic function like so:
let duckwrapper<'a> duck = ...
with the signature 'b -> 'a and where the returned value would be an object that implemented 'a (which would be an interface) and forwarded the calls to duck.
I've done this in C# using Reflection.Emit but I'm wondering if F# reflection, quotations or other constructs would make it easier.
Any suggestions on how to accomplish this?
EDIT
after reading Tims answer I thought I'd give a bit more details
What I was thinking of when I wrote about using quotations to help was something like:
{new IInterface with member x.SayHello() = !!<# %expr #>}
!! being an operator translating the quotation to a function and %expr being the unit of work for the method. I'd be able to translate the expression to a function (I guess) but wouldn't know how to
of course this wouldn't do the trick completely either since IInterface would be 'a which is where I hope F# reflection might have some handy functions so that I could construct a type based on a type object and some function values
EDIT
As an update to Tomas Petricek answer I'll give some code to explain my needs
type SourceRole =
abstract transfer : decimal -> context
and context(sourceAccount:account, destinationAccount) =
let source = sourceAccount
let destination = destinationAccount
member self.transfer amount =
let sourcePlayer =
{new SourceRole with
member this.transfer amount =
use scope = new TransactionScope()
let source = source.decreaseBalance amount
let destination = destination.increaseBalance amount
scope.Complete()
context(source,destination)
}
sourcePlayer.transfer(amount)
which is a try at porting "the" textbook example of DCI in F#. The source and destination are DCI roles. It's the idea that any data object that adhere's to a specific contract can play those. In this case the contract is simple. source needs a memberfunction called decreaseBalance and destination needs a member function called increaseBalance.
I can accomplish that for this specific case with let inline and member constraints.
But I'd like to write a set of functions that given an interface and an object. In this case it could be source (as the object) and
type sourceContract =
abstract decreaseBalance : decimal -> sourceContract
as the type. The result would be an object of type sourceContract that would pipe method calls to a method with the same name on the source object.
F# reflection (Microsoft.FSharp.Reflection) is an F#-friendly wrapper around the plain System.Reflection APIs, so I don't think it would add anything here.
Quotations can't define new types: (you'd need to define a new type to do your interface-based duck typing)
> <# { new IInterface with member x.SayHello = "hello" } #>;;
<# { new IInterface with member x.SayHello = "hello" } #>;;
---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stdin(7,4): error FS0449: Quotations cannot contain object expressions
> <# type Test() = class end #>;;
<# type Test() = class end #>;;
---^^^^
stdin(8,4): error FS0010: Unexpected keyword 'type' in quotation literal
Reflection.Emit is still the way to go with this.
Edit:
I hope F# reflection might have some handy functions so that I could construct a type based on a type object and some function values
I'm afraid it doesn't. Here's the documentation on F# reflection: http://msdn.microsoft.com/en-gb/library/ee353491.aspx
You can compile F# quotations using components from F# PowerPack. So I think you could use quotations to generate and execute code at runtime. If you write a quotation representing a function & compile it you'll get a function value that you could use to implement an interface. Here is a trivial example:
#r "FSharp.PowerPack.Linq.dll"
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.QuotationEvaluation
// Create a part using "Expr." calls explicitly
let expr = Expr.Value(13)
// Create a part using quotation syntax
let expr2 = <# (fun x -> x * %%expr) #>
// Compile & Run
let f = expr2.Compile()()
f 10
You can mix quotation syntax and calls to Expr, which makes it easier to compose code from basic blocks. The compilation is a bit stupid (currently) so the generated code won't be as efficient as usual F# code (but you'll need to measure it in your case).
I'm not quite sure I understand what exactly are you trying to do, so if you can provide more details, I can give more specific answer.