Current behavior:
Put a breakpoint on the case Twice(n) ... line.
On "step into" the control goes to x match { line
On "step into" the control goes to def TwiceTest = { line
On further "step into" the control goes to if (z % 2 == 0)... line.
Expected behavior:
Put a breakpoint on the case Twice(n) ... line.
On "step into" the control goes to if (z % 2 == 0)... line.
Code Snippet
object testobj extends App {
def TwiceTest = {
val x = Twice(21)
x match {
case Twice(n) => Console.println(n)
} // prints 21
}
TwiceTest
}
object Twice {
def apply(x: Int): Int = x * 2
def unapply(z: Int): Option[Int] = {
if (z % 2 == 0) Some(z / 2) else None
}
}
The current behavior is irritating while debugging a scala program with lots of nested extractors. I tried this with the new Scala debugger as well as the Java debugger but with the same result.
Step Filtering also does not help in this case.
As a workaround, I am putting a breakpoint in the unapply method and running resume from the first breakpoint. Can someone please suggest me a cleaner method.
Edit 1
I am using Scala-IDE (latest nightly build. 2.1.0.nightly-2_09-201208250315-529cd70 )
Eclipse Version: Indigo Service Release 2 Build id: 20120216-1857
OS: Windows 7 ( 64 bit)
The line number information in the bytecode is wrong. It is not an issue with the IDE, but the Scala compiler. When pattern matching is compiled, synthetic code sometimes gets the wrong position information.
I assume you are using Scala 2.9.2. In the next version of Scala (2.10.0), there are significant improvements in the pattern matcher, so it would be good to give it a try.
Related
I'm debugging v8 using lldb.
How can I print the string inside of Handle<String> Source?
The debug process is as follows:
(lldb) r
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
frame #0: 0x000000010100536b libv8.dylib`v8::internal::Compiler::GetSharedFunctionInfoForScript(isolate=0x0000000118008000, source=Handle<v8::internal::String> # 0x00007ffeefbfd4a0, script_details=0x00007ffeefbfd730, origin_options=(flags_ = 0), extension=0x0000000000000000, cached_data=0x0000000000000000, compile_options=kNoCompileOptions, no_cache_reason=kNoCacheNoReason, natives=NOT_NATIVES_CODE) at compiler.cc:2806:27
2803 MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
2804 solate* isolate, Handle<String> source,
2805 ScriptCompiler::NoCacheReason no_cache_reason, NativesFlag natives) {
-> 2806 ScriptCompileTimerScope compile_timer(isolate, no_cache_reason);
2807
2808 if (compile_options == ScriptCompiler::kNoCompileOptions ||
2809 compile_options == ScriptCompiler::kEagerCompile) {
Target 0: (d8) stopped.
(lldb) p source
(v8::internal::Handle<v8::internal::String>) $9 = {
v8::internal::HandleBase = {
location_ = 0x000000010f009a60
}
}
(lldb) p *$9
(v8::internal::String) $10 = {
v8::internal::TorqueGeneratedString<v8::internal::String, v8::internal::Name> = {
.....
}
}
Take a look at tools/lldb_commands.py. In short: configure your LLDB to load that script:
echo "command script import /path/to/v8/tools/lldb_commands.py" >> ~/.lldbinit
and then use the convenience commands it provides, the most important one being job, a mnemonic for "JavaScript object". It needs the raw pointer value that you'll see as ptr_ = ... somewhere in the output of p *$9, but you don't need to retrieve it manually. Example:
(lldb) job source->ptr_
0x28c008109019: [String]: "console.log('hello world');"
(Side note: tools/gdbinit tends to have a few more features than tools/lldbinit, because most folks on the team use GDB. We'd be happy to accept patches to improve LLDB support; relevant to the case at hand would be gdbinit's jh shortcut (allowing simply jh source) that currently has no equivalent in lldbinit.)
Issue
Following is a minimal, contrived example:
read :: FilePath -> Aff String
read f = do
log ("File: " <> f) -- (1)
readTextFile UTF8 f -- (2)
I would like to do some debug logging in (1), before a potential error on (2) occurs. Executing following code in Spago REPL works for success cases so far:
$ spago repl
> launchAff_ $ read "test/data/tree/root.txt"
File: test/data/tree/root.txt
unit
Problem: If there is an error with (2) - file is directory here - , (1) seems to be not executed at all:
$ spago repl
> launchAff_ $ read "test/data/tree"
~/purescript-book/exercises/chapter9/.psci_modules/node_modules/Effect.Aff/foreign.js:532
throw util.fromLeft(step);
^
[Error: EISDIR: illegal operation on a directory, read] {
errno: -21,
code: 'EISDIR',
syscall: 'read'
}
The original problem is more complex including several layers of recursions (see E-Book exercise 3), where I need logging to debug above error.
Questions
How can I properly log regardless upcoming errors here?
(Optional) Is there a more sophisticated, well-established debugging alternative - purescript-debugger? A decicated VS Code debug extension/functionality would be the cherry on the cake.
First of all, the symptoms you observe do not mean that the first line doesn't execute. It does always execute, you're just not seeing output from it due to how console works in the PureScript REPL. The output gets swallowed. Not the only problem with REPL, sadly.
You can verify that the first line is always executed by replacing log with throwError and observing that the error always gets thrown. Or, alternatively, you can make the first line modify a mutable cell instead of writing to the console, and then examine the cell's contents.
Finally, this only happens in REPL. If you put that launchAff_ call inside main and run the program, you will always get the console output.
Now to the actual question at hand: how to debug trace.
Logging to console is fine if you can afford it, but there is a more elegant way: Debug.trace.
This function has a hidden effect - i.e. its type says it's pure, but it really produces an effect when called. This little lie lets you use trace in a pure setting and thus debug pure code. No need for Effect! This is ok as long as used for debugging only, but don't put it in production code.
The way it works is that it takes two parameters: the first one gets printed to console and the second one is a function to be called after printing, and the result of the whole thing is whatever that function returns. For example:
calculateSomething :: Int -> Int -> Int
calculateSomething x y =
trace ("x = " <> show x) \_ ->
x + y
main :: Effect Unit
main =
log $ show $ calculateSomething 37 5
> npx spago run
'x = 37'
42
The first parameter can be anything at all, not just a string. This lets you easily print a lot of stuff:
calculateSomething :: Int -> Int -> Int
calculateSomething x y =
trace { x, y } \_ ->
x + y
> npx spago run
{ x: 37, y: 5 }
42
Or, applying this to your code:
read :: FilePath -> Aff String
read f = trace ("File: " <> f) \_ -> do
readTextFile UTF8 f
But here's a subtle detail: this tracing happens as soon as you call read, even if the resulting Aff will never be actually executed. If you need tracing to happen on effectful execution, you'll need to make the trace call part of the action, and be careful not to make it the very first action in the sequence:
read :: FilePath -> Aff String
read f = do
pure unit
trace ("File: " <> f) \_ -> pure unit
readTextFile UTF8 f
It is, of course, a bit inconvenient to do this every time you need to trace in an effectful context, so there is a special function that does it for you - it's called traceM:
read :: FilePath -> Aff String
read f = do
traceM ("File: " <> f)
readTextFile UTF8 f
If you look at its source code, you'll see that it does exactly what I did in the example above.
The sad part is that trace won't help you in REPL when an exception happens, because it's still printing to console, so it'll still get swallowed for the same reasons.
But even when it doesn't get swallowed, the output is a bit garbled, because trace actually outputs in color (to help you make it out among other output), and PureScript REPL has a complicated relationship with color:
> calculateSomething 37 5
←[32m'x = 37'←[39m
42
In addition to Fyodor Soikin's great answer, I found a variant using VS Code debug view.
1.) Make sure to build with sourcemaps:
spago build --purs-args "-g sourcemaps"
2.) Add debug configuration to VS Code launch.json:
{
"version": "0.2.0",
"configurations": [
{
"type": "pwa-node",
"request": "launch",
"name": "Launch Program",
"skipFiles": ["<node_internals>/**"],
"runtimeArgs": ["-e", "require('./output/Main/index.js').main()"],
"smartStep": true // skips files without (valid) source map
}
]
}
Replace "./output/Main/index.js" / .main() with the compiled .js file / function to be debugged.
3.) Set break points and step through the .purs file via sourcemap support.
I am following the "Little Go Book" by Karl Seguin, in order to learn Go.
My working environment is Visual Studio Code.
Upon debugging, when I try to call a function from the debug console, i get the following error:
"function calls not allowed without using 'call'", if I try using "call fib(10)", i get "Unable to eval expression: "1:6: expected 'EOF', found fib".
This is the function I am trying to evaluate:
//Fibonnaci
func fib(n int) int64 {
if n == 0 {
return 0
} else if n == 1 {
return 1
} else {
return fib(n-1) + fib(n-2)
}
}
If i try to call the function from the code itself ( from the main() for instance, it works perfectly).
However, if I set a breakpoint and try to call the same function from the debugger console, I get the below error:
Eval error: function calls not allowed without using 'call'
call fib(10)
Unable to eval expression: "1:6: expected 'EOF', found fib"
Failed to eval expression: {
"Expr": "call fib(10)",
"Scope": {
"goroutineID": 1,
"frame": 0
},
"Cfg": {
"followPointers": true,
"maxVariableRecurse": 1,
"maxStringLen": 64,
"maxArrayValues": 64,
"maxStructFields": -1
}
}
Looks like "Function calls via delve 'call' are not supported" yet github issue in microsoft/vscode-go repo :(
The issue vscode-go issue 100 "debug: support function calls via delve 'call'" just got closed with PR 101 and commit 5a7752c / CL 249377
Delve supports function calls. Even though it is still experimental and can be applied only to a limited set of functions, this is a useful feature, many vscode-go users long for.
Unlike other javascript/typescript debuggers, delve treats function calls specially and requires different call paths than usual expression evaluation.
That is because Go is a compiled, runtime-managed GC language, calling a function safely from debugger is complex.
DAP and VS Code UI does not distinguish function calls and other expression evaluation either, so we have to implement this in the same evaluateRequest context.
We use a heuristic to guess which route (call or expression evaluation) we need to take based on evaluateRequest's request.
This is part of the 0.17.0 milestone, yet to be released, and available for now in the nightly build.
this is a simple recursion function
func recursion(parameter : Double)
{
if parameter < 12
{
recursion(parameter + 1)
}
print(parameter)
}
when i am trying to put a simple value for example 0 or 1
recursion(0)
i get a compile error saying Missing argument for #1 in call any idea why this is happening?
btw if i change the function to
func recursion(parameter : Double)
{
if parameter > 1
{
recursion(parameter - 1)
}
print(parameter)
}
everything works fine
any ideas? i am using Xcode 7 beta
Your code works fine, just make a Clean & Build and then try it again and the initial compile error should disappear. Remember that Xcode 7 is still in Beta, Apple is working to fix this kind of false compile errors properly.
I hope this help you.
I come from a Python background, where at any point in my code I can add
import pdb; pdb.set_trace()
and at runtime I'll be dropped into an interactive interpreter at that spot. Is there an equivalent for scala, or is this not possible at runtime?
Yes, you can, on Scala 2.8. Note that, for this to work, you have to include the scala-compiler.jar in your classpath. If you invoke your scala program with scala, it will be done automatically (or so it seems in the tests I made).
You can then use it like this:
import scala.tools.nsc.Interpreter._
object TestDebugger {
def main(args: Array[String]) {
0 to 10 foreach { i =>
breakIf(i == 5, DebugParam("i", i))
println(i)
}
}
}
You may pass multiple DebugParam arguments. When the REPL comes up, the value on the right will be bound to a val whose name you provided on the left. For instance, if I change that line like this:
breakIf(i == 5, DebugParam("j", i))
Then the execution will happen like this:
C:\Users\Daniel\Documents\Scala\Programas>scala TestDebugger
0
1
2
3
4
j: Int
scala> j
res0: Int = 5
You continue the execution by typing :quit.
You may also unconditionally drop into REPL by invoking break, which receives a List of DebugParam instead of a vararg. Here's a full example, code and execution:
import scala.tools.nsc.Interpreter._
object TestDebugger {
def main(args: Array[String]) {
0 to 10 foreach { i =>
breakIf(i == 5, DebugParam("j", i))
println(i)
if (i == 7) break(Nil)
}
}
}
And then:
C:\Users\Daniel\Documents\Scala\Programas>scalac TestDebugger.scala
C:\Users\Daniel\Documents\Scala\Programas>scala TestDebugger
0
1
2
3
4
j: Int
scala> j
res0: Int = 5
scala> :quit
5
6
7
scala> j
<console>:5: error: not found: value j
j
^
scala> :quit
8
9
10
C:\Users\Daniel\Documents\Scala\Programas>
To add to Daniel's answer, as of Scala 2.9, the break and breakIf methods are contained in scala.tools.nsc.interpreter.ILoop. Also, DebugParam is now NamedParam.
IntelliJ IDEA:
Run in debug mode or attach a remote debugger
Set a breakpoint and run until you reach it
Open Evaluate Expression (Alt+F8, in menu: Run -> Evaluate Expression) window to run arbitrary Scala code.
Type what code fragment or expression you want to run and click on Evaluate
Type Alt+V or click on Evaluate to run the code fragment.
Eclipse:
As of Scala 2.10 both break and breakIf have been removed from ILoop.
To break into interpreter you will have to work with ILoop directly.
First add scala compiler library. For Eclipse Scala, right click on project => Build Path => Add Libraries... => Scala Compiler.
And then you can use the following where you want to start the interpreter:
import scala.tools.nsc.interpreter.ILoop
import scala.tools.nsc.interpreter.SimpleReader
import scala.tools.nsc.Settings
val repl = new ILoop
repl.settings = new Settings
repl.settings.Yreplsync.value = true
repl.in = SimpleReader()
repl.createInterpreter()
// bind any local variables that you want to have access to
repl.intp.bind("row", "Int", row)
repl.intp.bind("col", "Int", col)
// start the interpreter and then close it after you :quit
repl.loop()
repl.closeInterpreter()
In Eclipse Scala the interpreter can be used from the Console view: