Introduction to LLDB and the Swift REPL

Session 409 WWDC 2014

Learn how to use LLDB, Apple's state-of-the-art debugger. Learn how to analyze stack traces and diagnose bugs. See how you can test your hypotheses and explore your app's state with the Swift REPL.

Good morning.

I'm Sean Callanan.

[ Applause ]

Thank you, thank you.

I work on the Debugger Team at Apple and I'm really excited to show you this stuff today.

Now, a funny thing, before, when I was preparing these slides, I thought by the time I'm giving this talk, maybe some people have looked at the language manual for Swift, maybe some people have tried a Playground.

It's gone a little faster than that.

[ Laughter ]

I am really impressed.

You guys, I look on the labs, I look on Twitter.

You guys have apps started already, entire apps running in Swift.

I saw somebody with a raytracer.

It's crazy!

I... This is the sort of thing that makes me happy to be working at Apple.

You guys are such awesome developers.

It's really just an honor to write the tools you use.

Thank you very much.

[ Applause ]

So, I'm going to tell you about using LLDB and the Swift REPL.

Now, as you're writing a Swift app, you're probably going to write one or two lines of buggy code and that's where LLDB fits in.

Now, the good news is LLDB is better than it's ever been with Swift.

And I'm going to tell you about some of the basic features that LLDB has to help you find bugs in your program.

LLDB at its core is a tool to help you fix problems in your code.

It's got a great set of basic features for tracking down where your bugs are.

The first tool is the stack.

The stack is a tool that lets you look at why your program has stopped and what functions got called to get you to the point where your program stopped.

Now, your program doesn't always obediently stop where you want it to.

In that case, you need breakpoints.

Breakpoints are another great tool LLDB provides that let you stop whenever you want to.

Finally, no matter how you stop your program, we have a great expression command that lets you inspect your data right at the point where your program stopped.

In today's presentation, I'm going to show you these tools working with Swift.

The good news is, the commands are basically the same as they used to be but I'm going to show you how to find some familiar bugs that you may have seen before and also a couple of new ones that are introduced when you're working with Swift.

Now, the cool thing is this isn't all I have to talk about.

We now have a REPL, too.

The Swift REPL is built on top of LLDB.

You can access it just at the LLDB command prompt any time that you're debugging your program.

That's not all though.

You can also access the Swift REPL when you don't have a program running.

You can access it directly off of the shell prompt, for a clean slate.

I'm going to tell you lots more about interacting with the REPL later but there are two basic ways that we want you to use the REPL.

The first is when you've got a program with some code and you'd like to find out if it works, if it's doing what you expect it to, you can use this LLDB REPL to test your app interactively.

Another great use for this LLDB REPL is to add new code.

You can write new functions, new classes in an existing LLDB session and they get put into your code and they can interact with your code just as if you'd written them in your source files.

Now, if you've noticed, one theme this year, one thing that's kind of over and over we're seeing in all the presentations starting right at the keynote is how everything seems a little bit more alive.

Everything is a little bit more interactive.

Stuffs coming in, Craig is telling you about his hair, it's everything is much more immediate and LLDB is the same way.

Now we have a couple of tools that are, that have already existed that are very interactive and we're adding more this year.

First of all, you have the expression command as I alluded to earlier.

That's a great way for when you're stopped to poke at your variables, to call a couple of local functions.

We also have, if you're a little bit more experienced LLDB user or maybe you've watched some of our previous session videos, LLDB Python scripting.

I'm not going to tell you too much about that in this session but it's a great way to create new debugger features and automate your debugging processes.

This year, we've added Playgrounds which allow you to prototype entire new algorithms from scratch and learn APIs.

And we've also added the LLDB REPL.

Now what's the difference between the LLDB REPL and Playgrounds?

Playgrounds, as I told you and as you saw in Wednesday's demo which Rick and Connor showed you all the fantastic ways that you can use Playgrounds, Playgrounds works from a blank slate.

You've got a text editor, you import the stuff you want to import, then you write some code and you see how it works.

On the other hand, the point of the LLDB REPL is to let you investigate how code would work if it were inside your preexisting program.

Now, in today's session, I'm going to give you two basic things.

First, an overview of the kind of skills that you're going to want to apply just working with LLDB in your regular debugging.

And then, I'm going to tell you about some new debugging workflows that the Swift REPL enables.

Finally, I'm going to sum up and tell you where you can go for more information.

So, let's jump right into basic debugging.

Now in these slides, I'm going to show you interactions with LLDB, but really there's two basic ways of talking to LLDB.

So, one is if you're inside Xcode.

In Xcode, you have the debugger console which is usually at the bottom of your window when you're debugging.

You can work with the debugger console and enter commands and also Xcode provides you with a bunch of UI features that let you automatic that let you automate certain things like stepping.

There's another way of working with LLDB that some of you more experienced users may use from time to time, and that's the terminal.

The LLDB command line interface uses the exact same commands that you're familiar with, with typing in commands in Xcode.

I'm going to show you the command line interface but there's great sessions, as I'll tell you later, that tell you more about how to use it through Xcode.

Now, this is a situation that probably all of you have run into at one time or another.

You're debugging along in your program and your program crashes.

It's stopped and now the question is, well, what do I do?

There's all this information here.

There are a couple of basic questions that you should be asking that will help you find your bug as quickly as possible.

The first is what is the stop reason?

Why are we stopped?

The stop reason is a facility that LLDB provides that tells you why your program was told to stop.

Something makes it stop.

The next question is, all right, well, I know what that the program was told to stop, how did it get there?

What code ran to get us to this bad point?

This is where you use the stack as I alluded to earlier.

You want to look up the stack and find your own code so look through all the framework code, look through all the standard library code and find frames in your own code that are responsible for this.

Once you've located the place where things might have gone wrong, then you can start investigating the failure conditions, looking at your variables and seeing what variable values might have gotten you into a bad state.

So let's get started and look at applying these basic techniques to some crashes you might see out in the world.

Now, let's say your program's crashed.

The first question as I told you is you want to know the stop reason.

Why did it crash?

The command that helps you find this information is called Thread Info.

Now, I'm showing you two versions of the command here.

They both do the exact same thing.

It's just that the short version, t i, is very quick to type and if you're doing repeated stops and you're trying to get your work done quickly, you'll probably use short versions of commands.

There's also a long, long version of the command.

Now there are two reasons why this might be helpful.

The first is it's more explicit about what you're doing and the second thing is you can find it in the help.

So if you use the help command or the apropos command in LLDB, you can find this command very easily.

Now, let's say you typed "thread info" at the LLDB prompt.

You're going to get some information about the thread that's currently stopped.

There's two pieces of information that you want to know when you're crashed.

The first is what piece of code crashed?

In this case, we're stopped in a function called "Swift.-getOptionalValue".

Now the Swift underscore part the Swift dot part is very important here because it tells you that you're inside the Swift module.

The Swift module is the Swift standard library, so we already know that standard library code crashed.

Now, what was the reason that it gave for crashing?

The reason is a bad instruction.

Now, some of you may have seen this message before.

A bad instruction is when the CPU doesn't understand the instruction that's being given.

But wait a second, we've got a compiler that's being pretty smart about issuing the right instructions.

What's going on here?

Well, it turns out that 99 percent of the time, these bad instructions are used in assertions.

So, the code says if something is bad, if something unexpected is happening, I'm going to issue a bad instruction to the CPU and the program will stop.

So, when you see "EXC-BAD-INSTRUCTION", what you should be thinking is: assertion failure.

Now, what we can see from this stop reason without even looking at the stack or any of the stack frames is that we failed in assertion in the standard library.

Now what might cause that to happen?

OK, let's move on and have a look.

The next command you're going to want to use is the backtrace command.

The thread backtrace command prints all the frames on the stack of the current thread.

That is, it tells you what functions called each other on the current thread to get you to the point where you're stopped.

In this case, we see that just below the function that was actually stopped, you see your own code.

Now this top level code function may be familiar to you if you've played around with Swift's command line tools.

That's the code that's outside any function in your main source file of a command line tool.

So you recognize this top level code and you say, "Aha, this is my code.

Let's have a look."

Top level code is frame number 1, so that means we called directly into the standard library and an assertion failed.

Let's have a look at why that happened.

Well, we select the first frame and now we have information about the source code because it's your own code and we have that.

Here we see that that we've got an optional AnyObject that we got from a source that looks a little shady and then we unwrap that option without checking.

Well, turns out if you print the value of that unwrap, of that optional, you see that optional is None.

Well, that's not too difficult to fix.

You instead try "if let" and that will let you and that will make the unwrapping code conditional and they're actually being something in there.

Now let's take a little detour before we look at more examples.

If you're using Xcode, you're going to see more than just the stack that I just showed you.

If you're using libdispatch in your program, Xcode will additionally show you all the functions that got called in order to and enqueue your current block onto a queue.

Then after that, once the queue started running your code, you see the stack frames that your code invoked.

Now why is this relevant to this talk?

Well, all the stack frames that are above the last block execution, you'll be able to see local variables for.

However, all the local variables from before it got enqueued are not going to be available to you.

So you need some that's why they're grayed out in Xcode and you need to make sure you know, you remember that.

All right, well, Grand Central Dispatch is cool but we're focusing on LLDB, so let's get back to it.

Here's another case where we've got an assertion.

Now, I told you earlier that there's a command called "thread info" and that's a great way to find the stop reason for your current thread.

Another way to find both the stop reason and all the stack frames is just to issue the backtrace command.

If you do this in this case, we've crashed in a different spot, we see still that the reason we stopped is a bad instruction and we're still stopped in the Swift standard library.

In this case though, we're stopped in the getter for an array member.

Well, let's look at our own code.

Now this is a function in your own program.

On the left hand side, you see the main module and on the right hand side of the dot, you see the name of your function, in this case, FindElement.

Now what's this code doing?

FindElement is iterating across an array and for every element in the array, it's applying a function to it.

Once that function returns true, it returns that element of the array.

And if that function never returns true, the function returns nil.

There's some problem here.

Maybe some of you have figured it out.

But just, but the way I would look at this is I would look at the current index into the array again using the print command which is short for expression.

In this case, we see that the index is at the fourth element of the array.

Well, let's look at the array.

The count property of the array is 3, we've walked too far.

Well, what happened here?

We used array.count, right?

Didn't we?

Oh, not quite.

So here we have a case of misuse of the closed range operator.

We shouldn't have used the closed range operator.

We should at least have only used the half open range operator because, of course, the indexes of an array start with 0, so they end at count minus 1 instead of count.

But the real answer here is we shouldn't have been using the index at all.

We should have just been using forElementInArray and let Swift handle all the details of the indexing for us.

All right, well, let's look at another crash now that we've kind of seen the basics.

This crash looks a lot uglier.

Suddenly, there's a ton of frames on the stack.

What the heck is going on and all of this look like they're in libC++ABI and so forth.

Ohhh, scary.

[ Laughter ]

So, let's use our method and look through this systematically.

The first thing you see is that the stop reason is SIGABRT.

That means that we ran into a situation where the kernel had to put the kibosh on us and say, "Hey, no.

This is going too far.

You're cut off.

Stop." Why does that happen?

That often happens because an exception gets thrown.

Wait, a second, exceptions?

We're coding in Swift here.

All right, but they're still there if you look on the stack.

In fact, an Objective-C exception is being thrown.

All right, well, we've got to track this down so we look for our own code here and in fact we see again a function called FindElement.

This function is causing a lot of trouble.

Let's have a look at it.

So we select that frame and now we see our code again.

This time, FindElement is looking across an NSArray instead of a Swift standard library array.

Again, we've got this stupid coding error with the closed range!

But, the more interesting thing is: because we were using an NSArray, we were calling into Objective-C code.

Now, Objective-C code does throw exceptions.

Now, one, I took an unofficial survey of LLDB developers last night when I was sitting in bed and...

[ Laughter ]

...and the most popular crash by far was this one, EXC-BAD-ACCESS at address 0.

This means that you were trying to access memory at a bad address.

Nil tends to be a bad address.

So what's going on here?

I'm coding in Swift.

It's supposed to be safe.

Well, let's have a look and see what our top level code is doing here.

I go to that frame and I look at my code.

The code is importing Foundation and it's getting some NSData from a URL that looks kind of suspicious.

And then, it looks at the bytes property of that, of the resulting data and pulls out the first element of it.

What's the problem here?

Well, let's look at chars.

Chars is a null UnsafePointer.

We're working with Objective-C APIs.

Objective-C APIs can give you UnsafePointers.

This is so, your old friend, the null pointer, is still around and whenever you're dealing with UnsafePointers, you have to be very sure that you know what you're doing.

All right.

So, the lesson here is Swift is safe but the frameworks that you're working with may not be safe.

Let's sum up.

We've looked at a couple of different ways in which your code can crash and we've seen that the most important thing to look at is the stop reason.

The next thing, once you figured out what the stop reason is, is looking at the stack to find where your code fits into the picture.

Your code is going to have local variables and you can use the expression command to figure out what those local variables are and how they connect to the crash you're seeing.

Now, unfortunately, we don't always live in a world where your program stops when it's doing something wrong.

For that world, there's breakpoints (and also beer).

[ Laughter ]

You can use a breakpoint if any of the following things are true.

The first case is when the problem isn't a crash.

I've been showing you lots of cases where your program just can't move on because it tried to access something it shouldn't have.

But that's not the only kind of bug.

Your program might be outputting wrong data or it might be, you know, sending something embarrassing to a social networking site, that's a little tougher to set a breakpoint on but bear with me.

So, and there's another reason, you may just want to say, you know, "I saw the failing code on the stack, but I'd like to stop when that happens, not when the crash occurs."

Well, breakpoints are a great tool for all of these cases.

Breakpoints have a couple of attributes and you can edit them in Xcode really easily as well.

The most important part of a breakpoint is the specification.

When you say, "I want to stop at places that look like this," what that means to LLDB is, "this is a specification, I need to be listening."

Then, LLDB goes out and looks in the world for locations that match your specification.

Now, LLDB is clever about this, not only the locations that are already in your program when you issue the command have matched the specification...

But also, if you load a bundle or some other framework dynamically, LLDB is still sitting there in the background saying, "Oh, is there anything that matches my location in here?"

Finally, there's a couple of optional parts to breakpoints that are important and that I'll show you in a moment.

The first is the breakpoint condition.

The condition tells LLDB, "I only actually want to stop here when a certain predicate is true."

Finally, there are actions that you can perform without having to type any commands automatically when the breakpoint gets hit.

So let's look at some code.

Here I've implemented a very, very simplistic banking application based a little bit upon my own, like, wishes.

The bank account is, has a value that's represented in cents.

And you have two functions, you have a withdraw function and you have a deposit function.

Now your withdraw function is a little bit smart and it charges an overdraft fee when you go below, when you withdraw more than is actually in your account.

Now because this is my, kindof, wishlist this wish list account function this is actually an overdraft fee of 10 cents, but bear with me, this is just an example.

So, you want to stop exactly when an overdraft fee is charged.

That's over here on line 6.

And in order to stop there, you simply type "breakpoint set" with the file set to your current source file and the line set to 6.

The way you were doing this in Xcode is just click next to that line and that does the exact same thing.

Now, once you've set that breakpoint, you can look at the breakpoint list to see all those attributes I was talking to you about earlier.

The first thing that's relevant here is the specification of the breakpoint.

LLDB will tell you that you wanted this breakpoint at a certain file and a certain line.

The cool thing is LLDB also tells you all the locations it actually found for that breakpoint.

Now in this case, there's only one location but there might be more.

Now let's have a look at a case where there might be more locations.

But first, let's do a quick segue.

I've seen people that have tons of breakpoint set.

And one thing that can be frustrating is you've got a bug you're tracking down and you've got a bunch of breakpoints that you had set from an earlier, from debugging an earlier problem.

And you want to not stop at all of those.

Well, we happen to have the breakpoint disable command to let you do exactly that.

If you disable a breakpoint, you can obviously enable it later.

But for the time it's disabled, LLDB will simply ignore it and all of its locations.

Now, let's say we have a little bit different code.

This is a simple example where we implemented a function called "timestwo".

Timestwo applies to integers, it applies to doubles, and it also applies to strings.

I want to stop whenever any of these is called.

But wait, they've all got different line numbers, how am I going to do that?

In this case, we can use a symbolic breakpoint.

If I type breakpoint on timestwo, LLDB will say, "OK.

You want to match all functions that are called timestwo."

And it already tells you it found 3 locations for that.

Now if you do a breakpoint list, you see some more information that can be very valuable.

The first thing of course is your specification.

You said you wanted the name to be timestwo.

The next part is all the locations that LLDB found for your breakpoint.

In this case, it found the location where you were processing an int and returning an int.

It also found the same thing for double and the same thing for string.

OK, that's cool, what can I do with this information?

Well, let's say you only care about the case where you are handling a string.

In that case, you can disable all the locations except the ones you care about.

Now this is of course handy when you have source code.

But if you don't have source code this is even better.

You may be saying to yourself, "Well, I'd really like to know when I'm in this array subscript operator from the standard library."

Well, why not use a symbolic breakpoint?

We don't need source for that.

And then you say, "Well, oh I set the breakpoint on the subscript operator but there's a bunch of them."

Well, that's OK too.

Just disable the locations you didn't want.

There's another cool way of doing this that uses a scale called "regular expressions".

Now, some of you may have worked with regular expressions before, and if so, you're always looking for new ways to use them.

[ Laughter ]

This is actually a joke from another of my colleagues who used to give the talk, so blame him.

When you set this breakpoint, you say, "I want to stop at timestwo followed by any sequence of characters as long as there's the word 'string' in there."

So now, you've broke you've set a breakpoint specifically at the "Swift dot"...

uh, at the version of timestwo that handles Swift.String.

All right, well we've got regular expression breakpoints.

That's really cool.

What else can we do?

Well, we can use regular expression breakpoints for other types of categories of functions.

So for example, if you want to stop on all methods of a certain class, you say, well break set on the regular expression "Account.". Why all these backslashes?

Well, the reason for that is that we want to make, we want "dot" to actually be a dot here.

We don't want it to mean any character.

In regular expressions that would normally mean any character.

You can do the same thing with functions in a module.

Although, watch out.

Once you start setting a breakpoint on all functions in a module, you're going to find out there are a lot of functions in a module, including some automatically generated ones, so you want to watch out for that.

There's a lot more on regular expression breakpoints and a couple of other, you know, topics like that in the Advanced Debugging with LLDB talk that we did last year.

That should all still apply to Swift as well.

All right, back to our examples.

Now let's say you've applied symbolic breakpoints, you've set some file and line breakpoint but it gets hit all the time.

And you're like, "Oh man, this is really tedious to keep pressing continue, can't there be a better way?"

Well, in fact there is a better way.

Now let's go back to our bank account example.

And let's say, we're being extremely gracious and we're not charging an overdraft fee.

But we find that the users of this bank account tend to be kind of irresponsible in their spending.

Again, we can set our breakpoint on the withdraw function.

But now, once we've set the breakpoint, we'd like to know: "When would we charge an overdraft fee (if we were to charge one)?"

The way we find this out is by setting a breakpoint condition on the breakpoint.

Now, a condition is simply a Swift expression that evaluates to either true or false.

If the Swift expression evaluates to true, then LLDB stops at that breakpoint.

If the condition evaluates to false, LLDB automatically continues and you'd never see it.

Another thing you might want to do is, instead of just stopping when you would charge an overdraft, you'd like to see what kinds of amounts are people withdrawing from their bank account?

What is their balances looking like?

You can do that too.

In this case, you use a facility called breakpoint commands.

Breakpoint commands are really cool because they really minimize the number of times where you have to stop your program.

If you say "breakpoint command add", you can add the break, add commands to the last breakpoint that you created.

In this case, what we want to do is see the local, the value of the current account in cents.

And then we want to continue, which means that the process just keeps running as normal.

Finally, once we're done typing in commands we type capital D O N E.

And then, when you run your program, you get output each time the breakpoint gets hit.

But you don't have to touch anything.

This is a really cool feature that is very useful for when you've got your program but you don't want to have to recompile it to insert print lines or do something horrific like that.

Now, there's a little bit of a caveat here when you're using mixed projects.

Breakpoint conditions and breakpoint commands both use expressions in the language where the breakpoint is located.

Now, if you set a breakpoint on a symbol that...

there might be breakpoints match there might be locations matching that breakpoint at multiple places in your program: some of them implemented in Objective-C; some of them implemented in Swift.

Now, we thought about that.

So we've provided the ability to set breakpoint conditions and breakpoint commands on specific locations of a breakpoint, not just on the breakpoint as whole.

So, if you're stop if you've got a breakpoint location in Swift, you can type in a Swift condition.

And if you've got another location in Objective-C, you can use Objective-C in your condition.

Now that raises the question, "Well, OK, I set a symbolic breakpoint.

Now I've got a ton of locations, how do I tell them apart?

How do I figure out what language they're in?"

Well, I'll give you a quick overview of how to read symbols.

In this case, we're looking at a couple of different symbols in different that are implemented in different places in your code.

The first is called "main".

If you're an Objective-C or C programmer, you'll recognize that main is the main entry point of a C program.

But the more important thing to notice here as that they're it doesn't have any argument names and it doesn't have any adornment.

This typically means that it's a C or Objective-C function.

There's another thing, though, that you have to remember...

Especially with, when you're dealing with Swift, and that is the top level code acts the same way.

So just remember that if there's no adornment like this, it's either Objective-C or C or if it's top level code, then it's Swift.

The next thing is, if you have an Objective-C class or instance method, that class or instance method name is going to have brackets and a dash or a plus sign.

Finally, if you have a Swift function, then we know the return type and we know the argument types for the function, so we're going to be very verbose and tell you all that information right up front.

All right.

So, now we've seen how to stop an app at the right time in LLDB.

The tool you use to do that is breakpoints.

You can set breakpoints based on all kinds of filters and you can even set conditions on your breakpoints, so that once you know where you want to stop, you can also tell LLDB, to some extent, when you want to stop.

You can even set automated actions on your breakpoints so that you don't have to stop, investigate your variables and then move on.

Well, now let's talk about some of the new stuff that we've added into LLDB.

This is the stuff I've been having fun with for the last year or so.

The first thing I'm going to tell you about is validating your existing code using the LLDB REPL.

The LLDB REPL is really an amazing tool.

And these slides, while they kind of scratch the surface of all the stuff you can do, I'm really excited to see what you all can do and what kinds of workflows you're going to discover.

So let's try validating some existing code, but first, let's figure out when we can do that.

Well, the REPL and the LLDB command line exist in harmony with one another.

You can launch the REPL from a shell with an empty target just by typing "xcrun swift" as I told you earlier.

However, also when your program is stopped at any point, you can type "repl" and you get to a REPL prompt just the same.

Finally, you can break back into LLDB by pressing colon-enter and that drops you back into the LLDB prompt.

Why this weird colon-enter thing?

Well, there's another thing that colon can do for you.

If you're stopped in the REPL, you can use the colon prefix and type an LLDB command after it.

And that LLDB command will be executed just as if you typed it at the LLDB prompt.

This is a really handy way and it shows that really LLDB and the REPL are living right next to each other.

All right, enough with the explanation, let's go right in to the code.

So I've written a function here and it does a partition of an array.

Now you may be asking yourself, "OK, what kind of partition are we talking about here?"

And maybe you have the implementation handy or maybe you don't.

How can we use the REPL to discover more about this function?

Well, with our program stopped, we drop into the REPL.

And then we can call the partition function right from there.

If we send it the array "3, 4, 5" now what we get back is the array containing 3 paired with the array containing 4 and 5.

All right, this looks interesting.

I guess there's something about that being the bottom part of the array and the top part of the array.

Let's formalize this.

Let's test the theory about what's going on.

What I'm going to do is now write my own code in the REPL.

The expression command is really great for one liners but the REPL command is awesome for editing your code and adding entirely new functions.

In this case, we're going to write an "ispartition" function.

That ispartition function iterates across all the members of the left-hand array and checks that they're less than or equal, that they're less than or equal to the numbers in the right-hand array.

If any of them are greater than a member of the right-hand array, it says, "Oh, this doesn't look like the kind of partition I was expecting," and returns false.

Finally, once it's checked everything it returns true.

You can run this ispartition function on the result of partitioning a larger array.

And this partition will tell you indeed that was, the result was a partition.

This is something fairly deep.

You've got a function that exists in your code already, you've compiled it using the Swift compiler.

Swift isn't an interpreted language or anything.

But at the same time, you've used this REPL to interactively test by adding new code.

This is just one of the kinds of interactive debugging scenarios that we're hoping will change the way you work with code.

Let's look at another example.

Using this partition function, I've implemented a sorting algorithm called "mysort".

Now I want to validate that mysort works.

Well, I can enter the REPL again.

If I enter the REPL, I can run mysort on an array and the result is that the array is the result is an array that I can kind of eyeball and see as sorted.

All right, cool, well it fit on the slide, it looks sorted to me, this is probably good enough.

But many of your real data structures aren't going to fit on a slide and you can't easily eyeball them for correctness.

Let's write a function that checks whether an array is sorted.

In the REPL, we just type, we start defining a function called "issorted".

The notion here is: we're going to keep track of the previous element that we saw of the array.

And for each element in the array, we're going to check: is it indeed greater than or equal to the previous element?

If there's ever an element of the array that is less than the previous element, then we know, "oh, this array isn't sorted."

Now why are we using an optional for the previous element?

Why is last an optional?

Well, the first element of the array doesn't have a previous element.

So the last element in that case is going to be nil.

If I run issorted on the result of using my compiled mysort function on an array, I see indeed that the mysort function was implemented correctly for this case and returned, and the issorted function returns true.

This is the kind of ad hoc unit testing that I was talking about.

Now, let's take another example.

But instead of validating existing code, we'd like to try out some new code in our program.

And this is a good example to kind of review the role that the expression parser and the REPL have in your program.

When you're running your program, you have two aspects of your program state.

The one aspect is your stack: that's all the functions that your program'ss called, all the threads that you're currently looking at.

For investigating those, we think the expression command is a wonderful tool.

However, there's all this code that you've written that may not be currently running, you may not have a stack frame representing it, but you'd still like to play around with it.

That's where the LLDB REPL comes in.

They're both built on the same technology but they both, but they serve distinct purposes.

Let's look at an example: dispatching on a queue.

In my program, I've imported Foundation and I've declared a dispatch queue using dispatch-queue-create.

This code has set up a queue inside my program and I can dispatch blocks onto it.

Well, from the REPL, I can do the same thing.

I stop my program, enter the REPL, and then I call dispatch-sync on the queue and add a block that prints "world".

Indeed, if I do that, I get the output "world".

Now there's one thing to remember here.

Your program is stopped when we talk, when we do this.

So let's say you had a queue that was running in your program that was already running some of your code.

Now, if you try to dispatch to it, that dispatch isn't going to, that dispatch isn't going to return because there's something happening on the queue already.

What you should do in that case is dispatch-async your block, and then you can continue your program and your code will run.

This is a great way to manipulate a resource that needs to be serialized on from the debugger.

And actually it lets you debug in a more safe way.

Let's look at another example.

In this example, I've got a protocol.

This protocol says, "I'm a type of thing that can be doubled."

And in my code, I've implemented an extension to this built-in Swift integer class that makes it be doublable.

So calling twice on an integer now returns 2 times that integer.

Using that protocol, I've implemented a generic function that knows how to get 4 times something by doubling it twice.

The REPL can mess around with this stuff too.

We can write an extension on the Swift built-in string class that makes it doublable right in the REPL.

We can make "twice" concatenate the string with itself and return the result.

And then, we can run print, and then we can run 4 times on the result of that and 4 times works because we're able the REPL is able to register that extension.

So then we see the output three, four times just as we expected.

Now, this is just the beginning.

And I'm sure that next year I'm going to be, or I am or someone of my colleagues is going to be telling you about all the cool new debugging workflows that your colleagues have found and we're going to have a pretty fantastic session next year.

But let's sum up and tell you about what other resources there are to help you out.

LLDB provides great tools to diagnose bugs in your program.

I've told you about stop reasons, the stack, I've told you about the print command (or expression if you like), I've told you about breakpoints, and I've also told you about the great new LLDB REPL that lets you debug in an interactive way: writing your own code and interacting with your program's existing code.

If you want more information on this, first of all, you can contact our awesome Developer Tools Evangelist, Dave DeLong.

You can also check out the Quick Start Guide in our documentation.

The LLDB Quick Start Guide is a fantastic document and it will tell you lots of stuff that I haven't covered here.

Finally, you can communicate with other developers and chat about LLDB and the kinds of workflows you discover on the Apple Developer Forums.

But that's not all, it turns out we have a great session for you on Friday morning.

It's going to be just the thing to go with your morning coffee because my colleague Enrico Granata is going to tell you some really neat stuff that LLDB does to help you under the hood in debugging your Swift programs.

Another thing that you want to check out is the "Debugging in Xcode 6" talk.

That was earlier this week so you want to check that out online but it tells you all about the UI implementation and how to deal with, for example, the Grand Central Dispatch integration.

Finally, as I told you earlier, we had a session last year where we talked a little bit more in depth about working with LLDB and especially about breakpoints and stepping.

Again, I want to reiterate, thank you so much for being Apple developers.

Thank you so much for working with LLDB.

I look forward to seeing you in the labs.

[ Applause ]

Apple, Inc. AAPL
1 Infinite Loop Cupertino CA 95014 US