In my app, I have a problème when I try to reach an index in an Array, the Array is actually empty. I cannot find what is emptying it so I was wondering if it's possible with the debugger to create a dynamic breakpoint that will pop up when my array is empty. So as soon as something is either resetting the array or taking away its last object, I'd like to know.
I tried to create a symbolic breakpoint with "myArray.isEmpty == true" as the condition but it doesn't look to work the way I want.
Is it possible or I'm just dreaming?
Thanks
As #kendall mentions, you could use didSet to detect when the array is being emptied, and put a breakpoint on it:
// a acts like a normal variable
var a: [Int] = [] {
// but whenever it’s updated, the following runs:
didSet {
if a.isEmpty {
// put a breakpoint on the next line:
println("Array is empty")
}
}
}
a.append(1)
a.append(2)
println(a.removeLast())
// will print “Array is empty” before the value is printed:
println(a.removeLast())
What you want is called a Watchpoint, which lets you monitor changes in memory. I'm not sure yet how to set one on a Swift Array, but that could be a good starting point for research.
One idea would be to add a didSet{} block to the property that holds the array, adding a log statement within - break on that based on your condition that the array is empty.
To the best of my knowledge this isn't possible with Swift and Xcode (or with any other language of IDE I have used). To make this work the IDE would have to continually evaluate the given expression at every step of programs execution.
Now, if arrays were classes, you could subclass and add a breakpoint in an override isEmpty method, but as they are classed you cannot. :-(
Related
I'm trying to program a numerical method in my ti-89, in TI-Basic language, the problem is that when I overwrite the variable inside the loop it doesn't do it, I'm new to this language and I don't know if I'm omitting some detail behind
Item()
prgm
Input "f(x)",a //call the function in text mode
define s(z,t) = a //convert the text into a function
local xa,ya //declare local variables
x->xa //assign values that I already have saved to local variables
y->ya
local i
For i,1,10
s(xa,ya)->xa //evaluate the function, and I have to rewrite the first parameter
EndFor
EndPrgm
I'm not entirely sure what's causing the problem, but I would try using a list to store the data instead if that is all there is. You can rewrite the list and clear it easily. You can store strings in these lists as well. Lists can be edited at all times, which will fix your problem. Although this solution might not be as efficient, it should work. I don't have my calculator with me so I can't test it, sorry :(. These two functions below add things to the list and clear the list.
L1(x,y,z)
ClrList L1
Good luck! TI-Basic can be difficult sometimes
I have let intervalId = option(Js.Global.intervalId)
I would like a succinct way to do the side effecting call to Js.Global.clearInterval if the option has a value (ie. is Some(id) and not None)
Maybe the Belt.Option.map function is the answer, but I'm having problems putting it to use.
I'm very new to OCaml and ReasonML, but several languages I know have suitable functions. I'm paraphrasing some of them here to give the idea what I'm looking for:
In Scala I would say: intervalId.foreach(Js.Global.clearInterval)
In Swift I would say: intervalId.map(Js.Global.clearInterval)
Belt.Option.map(intervalId, Js.Global.clearInterval) should work fine, except it returns a value that you need to discard in some way to avoid a type error or warning.
The safest way to discard values you don't need is to assign it to the wildcard pattern and include a type annotation to ensure the value you discard is what you expect it to be:
let _: option(unit) = Belt.Option.map(intervalId, Js.Global.clearInterval)
You can also use the ignore function, which works particularly well at the end of a sequence of pipes, but beware that you might then accidentally partially apply a function and discard it without actually executing the function and invoking the side-effect.
intervalId
|> Belt.Option.map(_, Js.Global.clearInterval)
|> ignore
For curiosity, I'll leave the obvious thing I had here before the chosen answer:
switch (intervalId) {
|Some(id) => Js_global.clearInterval(id)
|None => ()
}
I noticed that application.applicationVariants.size() always returns 0, although I know there are variants, since I can iterate them: android.applicationVariants.all {println it}. Because of that I am also not able to iterate the collection with each.
What am I missing here?
This is normal behavior. Notice this sentence in the changelog (v 0.5.5):
access to the variants container don't force creating the task. This
means android.[application|Library|Test]Variants will be empty during
the evaluation phase. To use it, use .all instead of .each
I have a unique situation with setStringValue: and hoping someone could clear this up:
Using the following theoretical example (not literal) code:
NSString *myVar;
[myOutlet setStringValue:myVar];
It appears that for any string value such as:
myVar = #"hello";
a pointer is passed to myOutlet and the NSTextField points to the same memory location as myVar, essentially making them identical. In essence:
myVar == [myOutlet stringValue];
returns TRUE.
HOWEVER
in this situation:
myVar = #"";
it seems as if it is not passing a pointer, but rather NSTextField is creating it's own independent memory location to store it's empty string, essentially:
myVar == [myOutlet stringValue];
return FALSE.
Can anyone confirm whether this is true, and if so, explain why? I believe this to be the source of a very complex problem I'm having in a piece of code I'm working on and I'm trying to wrap my mind around the root of the problem.
Thanks!
Basically, it's pure chance that the first situation works out. These pointers are absolutely not guaranteed to be equal, and if you need to compare strings, use -isEqualToString: always.
What you're running into is probably an optimization of some sort, to avoid storing #"hello" more than once. We have no way of knowing when this will or will not happen, and it may change in the future, or from device to device.
When debugging a function I usually use
library(debug)
mtrace(FunctionName)
FunctionName(...)
And that works quite well for me.
However, sometimes I am trying to debug a complex function that I don't know. In which case, I can find that inside that function there is another function that I would like to "go into" ("debug") - so to better understand how the entire process works.
So one way of doing it would be to do:
library(debug)
mtrace(FunctionName)
FunctionName(...)
# when finding a function I want to debug inside the function, run again:
mtrace(FunctionName.SubFunction)
The question is - is there a better/smarter way to do interactive debugging (as I have described) that I might be missing?
p.s: I am aware that there where various questions asked on the subject on SO (see here). Yet I wasn't able to come across a similar question/solution to what I asked here.
Not entirely sure about the use case, but when you encounter a problem, you can call the function traceback(). That will show the path of your function call through the stack until it hit its problem. You could, if you were inclined to work your way down from the top, call debug on each of the functions given in the list before making your function call. Then you would be walking through the entire process from the beginning.
Here's an example of how you could do this in a more systematic way, by creating a function to step through it:
walk.through <- function() {
tb <- unlist(.Traceback)
if(is.null(tb)) stop("no traceback to use for debugging")
assign("debug.fun.list", matrix(unlist(strsplit(tb, "\\(")), nrow=2)[1,], envir=.GlobalEnv)
lapply(debug.fun.list, function(x) debug(get(x)))
print(paste("Now debugging functions:", paste(debug.fun.list, collapse=",")))
}
unwalk.through <- function() {
lapply(debug.fun.list, function(x) undebug(get(as.character(x))))
print(paste("Now undebugging functions:", paste(debug.fun.list, collapse=",")))
rm(list="debug.fun.list", envir=.GlobalEnv)
}
Here's a dummy example of using it:
foo <- function(x) { print(1); bar(2) }
bar <- function(x) { x + a.variable.which.does.not.exist }
foo(2)
# now step through the functions
walk.through()
foo(2)
# undebug those functions again...
unwalk.through()
foo(2)
IMO, that doesn't seem like the most sensible thing to do. It makes more sense to simply go into the function where the problem occurs (i.e. at the lowest level) and work your way backwards.
I've already outlined the logic behind this basic routine in "favorite debugging trick".
I like options(error=recover) as detailed previously on SO. Things then stop at the point of error and one can inspect.
(I'm the author of the 'debug' package where 'mtrace' lives)
If the definition of 'SubFunction' lives outside 'MyFunction', then you can just mtrace 'SubFunction' and don't need to mtrace 'MyFunction'. And functions run faster if they're not 'mtrace'd, so it's good to mtrace only as little as you need to. (But you probably know those things already!)
If 'MyFunction' is only defined inside 'SubFunction', one trick that might help is to use a conditional breakpoint in 'MyFunction'. You'll need to 'mtrace( MyFunction)', then run it, and when the debugging window appears, find out what line 'MyFunction' is defined in. Say it's line 17. Then the following should work:
D(n)> bp( 1, F) # don't bother showing the window for MyFunction again
D(n)> bp( 18, { mtrace( SubFunction); FALSE})
D(n)> go()
It should be clear what this does (or it will be if you try it).
The only downsides are: the need to do it again whenever you change the code of 'MyFunction', and; the slowing-down that might occur through 'MyFunction' itself being mtraced.
You could also experiment with adding a 'debug.sub' argument to 'MyFunction', that defaults to FALSE. In the code of 'MyFunction', then add this line immediately after the definition of 'SubFunction':
if( debug.sub) mtrace( SubFunction)
That avoids any need to mtrace 'MyFunction' itself, but does require you to be able to change its code.