Debugging Clojure Code Wtih Cursive

0 0

hi everyone so my name is Colin and I'm here to talk to you about cursive as usual my favorite topic of conversation so for those of you who aren't familiar with cursive it's not EE for developing enclosure code and I'm still working on it it hasn't had a version one release yet but it's getting very close to a version one although admittedly I used the slide at the college last year almost this exact same slide so who knows maybe next year I'll be back with the same slide we'll see but I hope not so the first public beta was about eighteen months ago and there's been a really great response since then there's there's a lot of people using there's a ton of people using cursive every day to do the work and it's yes had a really great response it's a plug-in to IntelliJ at the moment so for those who aren't familiar with IntelliJ it's a Java IDE I think it's the best Java IDE it's been around for years and the jetbrains the company of the maker is full of really smart people so intelligible product they have it used to be purely commercial and now they have a split the IntelliJ community edition there's open source it's all apache license you can do what you want with it and that has Java so all the sort of base Java support that you need maven and all the build tools get all that stuff and then the Community Edition sorry the Ultimate Edition builds on top of there and it has a bunch of closed source components for j2ee and a lot of web dev stuff and wet but cursive works fine with the free edition you can just download the free one and it'll work fine with that so IntelliJ always always been jetbrains flagship product but a couple of years ago they split it out in two and they made it basically into like an IDE building platform and then the Java idea was really just to sort of plug in into that like any other plugin so it's still a somewhat blessed special plugin but it's that's more or less than what it works and then JetBrains went on to build a bunch of different ideas on top of that so they have ideas for Ruby for Python for PHP Objective C C++ they just released the other day and so cursive I will actually be able to release a standalone IDE as well so it'd just be a single thing you download for Windows Mac and Linux and it'll be like a lightweight standalone closure focused IDE it is going to be commercial I will be asking for your money I'm just so dick it out of the way upfront and it'll be it'll cost more or less the same as the smaller JetBrains ATVs so I'm here specifically today to talk about the debugger so IntelliJ it's obviously been a Java ready forever so they've been debugging Java code for for a very long time so they have a basically JVM debugger built in so you can use it for Scala for any it for a groovy any of the jvm languages it supports and encourages specific functionality it's based on the J PDA which is the so the JVM actually provides really really good debugging facilities the J PDA is the Java platform debugger architecture and the specific component that has a whole bunch of different components and the specific one it uses is the JDI so that's a series of java classes that you can use to write debugging tools in Java so one questions a lot of people ask is why would I need it if I get if I have a ripple write and and I do think it's true that the ripple fulfills a lot of the need that people previously use the debugger for so if you're using something like Java for example the language is quite static and you compile it up front and then you execute it and the only way that you can really stop your program and kind of look inside it and see what's going on is with the debugger and was really the only way you could explore the execution of your program so I do think it's true that some of the use case that people previously used to bug is for you can now use a ripple for so particularly if you you know you're working in the ripple you're developing small functions you can test them all independently and then you can compose them together and test the the larger blobs that previously people might have used the debugger for that and now obviously the ripple fills that need but some code is just really really hard to explore in the ripple so and my work for example cursive builds on the IntelliJ framework that's like there's millions of lines of Java code it's all stateful that's mutable and it's just really really hard to explore on a ripple so I mean I do have a ripple on my open IntelliJ instance and I can play around with theirs and I can test things but it's not the same as if all the code was closure that I wrote myself and I think the same is probably true of very large closure code bases so those of you working in large companies multiple developers maybe you don't understand ponen written by somebody else works in my case somebody else is myself three months ago and I still can't figure out how it works half the time so no cursive has a lot of different components so I work on one and then I work on something totally different for three months and I have to go back to the previous one and just stepping through it is just much easier and problems with concurrency and much much easier to debug than to them and the ripple I mean sometimes you just need to be able to stop the world you can look at all the threads you can see what your threads are doing you can see how they're interacting that's much more difficult to do to doing a ripple and the other argument is that maybe a debugger stops people thinking about their problems and they just fire up the debugger instead of thinking about it I'm a huge fan of thinking I think myself I recommend you all think as well but sometimes it's not enough right it doesn't matter how long I'm in a hammock I'm never going to understand I'm never gonna burst and the IntelliJ framework any better it's only documented at a very superficial level and its massive it's just enormous so rather than actually just talking about a debugger which is kind of boring I thought I would show you a debugger which is much more exciting for all involved so I have some example code here this is an example taken from the joy of closure I have - I had some examples from the joy of closure and close your programming find books both I recommend them so this is one from the joy of closure just looking up a chess board so we have some code here this is a representation of a chess board just a victor with a series of characters and the characters the positions and the victor represent the piece that set that board and then we have this function look up here which takes we can see how it's used down here so it takes a position and cheers' notation and it will tell you what it is so we can place a line breakpoint here hopefully and then we can just run this as a script and debug it and it stops there so no muss no fuss that's very easy so I'm in the interest of time there's a lot to talk about I'm going to assume that most of you have probably at least seen a debugger or perhaps used by on the society by go before so I'll go through this pretty quickly so down here on the on the lis we have the thread view so this is the stack of execution that shows how we got to where we are at the moment for those of you with morbid fears a jar of Java stack traces this is where they come from and you can see that this is actually pretty similar it has all the same information that you were getting a stack trace so the method the line number and so on here you can look at all the different threads and here there's only a couple here cuz it's just a script but in a larger application you can see all the threads here you can flip between the threads and see what the thread of execution is it's quite useful the other nice thing here is you can see that these ones here have have a kind of yellowish color I'm actually color blind so I'm assuming this yellowish but this color here anyway this is lines of execution that are not in your program so these white ones here are lines that are actually in my program and these other ones here come from external dependencies so they're either come from the JVM or they come from some library that using in this case they mostly come from closure itself and and we can actually filter those out so we just see the lines that that are from our program which is quite nice and you can go back through the through the execution it will take you to that point and the execution and show you how you got to where you are and then on the right here you have your variables view so this shows the this object that's obviously more important if you're working with Java so that this debugger is still fairly Java focused and that kind of leaks through a bit I'll talk about more about that later on so you have you this object which is not so useful in closure I mean it's generally the class that's compiled from the current function that you're executing but it is still useful sometimes and we'll see a bit about there and a wee bit and then you see your local variables here so board and pause which were passed in and then we have this funny Vik 17 they'll talk about a bit later on so there's quite nice we can see everything here and then there are other ways we can actually see so I can hover over a symbol here and it will pop up it will evaluate it and pop up the value of it right there and if it's a more complicated funk structure I can actually open that out and then we can drill down into it and see so this is obviously pretty simple it's just a victor of characters but if it were a sort of nested met with victors and one that you can drill down into that and see it that's quite nice and you can see the locals are actually painted into the editor here as well or a sort of representation of them that has to be painted on a single line so collections you just get a summary because have actually renders lazy sequences as well that tell you how many elements and the sequence have been realized and things like that and the values are actually painted right in there so that's actually really useful and just as you're going through you can see the variables that are kind of relevant to where you are right where you need them that's quite nice and so when you're actually just hovering around like this it will actually only evaluate symbols that won't evaluate expressions because they might have side effects and you don't want you you know your database being written to what he's just hovering around in your source code but if you do what you want to do there you can actually just evaluate this expression here to you and I can X you evaluate that's different cause we're really keen and it'll give us back a function so this is actually going out to the debug JVM and just execute the code on the JVM like any other code so that's quite nice and it's really useful to be able to even look at functions coming up to see what the return value will be when you get there again as long as your functions are pure a few functions have side effects and all bits are off but that's that's more lesser and you have all your standard sniffing commands as well so I used to step over before which just dips to the next line we can step in here and go up here we can step in there and see again the locals are all painted in the editor and we can also step out which again these are very short functions but that will run to the end of the function and take you back to the the point their function was called from and the other nice thing to notice which actually the screen here is a little bit small but and the variables view here it actually shows the value of the last function invocation as you're stepping through and this is really nice so you can step into a function and then immediately step out of it and just to see what the return value is as you're going through as you step in through your code which is which is also quite nice the other thing you can do here is you can drop a stack frame so let's say we drop the stack frame here so there were just the top stack frame it will completely blow it away and take you back to where you were previously so what your local variables get dropped and assuming that your function is pure that you're not you have any side effects there's just like a back in time basically so what will actually often happen when you're debugging you have an eye dear of where your program is starting to go wrong so you're stepping through your function and you're looking at your variables and all of a sudden you'll notice that your variables have started to go bad and you've actually either you accidentally pushed if7 too many times or or you weren't quite sure where it actually started happening and when you can start to see your variables going bad you can actually go back and then just re execute that function again to see what happened again as long as there are no side effects if there are side effects like if your function is memorizing something then the next time you come back you'll get the memorized value which may or may not do what you want and right for those of you who may be a little bit IDE phobic and you can see me using my mouse for all of this you can drive all this with the keyboard IntelliJ you can do pretty much everything with the keyboard it's just a little bit easier in a demo to show what I'm doing with the mouse so now obviously this is Clojure we don't want to be running scripts it's kind of awful so we will run this in ripple if it will actually I can't see on the screen still annoying you know why that font is really big so this is this is a ripple here basically and it's actually being run in debug mode so what we can do will just comment it out so it doesn't get run immediately so we can load that namespace and to the end of thing we'll switch the namespace and now we can execute that function and it will stop so again it's the ripple is totally interactive you can load code on it or whatever and you can debug the code at the same time which is quite nice and so we can go through there and if I execute the same code here the ripple will stop as well so there's a nice it gives you this sort of I mean when someone asked me why would I need a debugger if I have a ripple I would ask why don't you want both I want both and so here we are we have both so we can do some more quite neat things and just so the breakpoints are configurable I can hover over this breakpoint here and we get a bit of a summary of what the what the breakpoint is doing and then I can control click on it so there's various things we can do to it we can enable it and disable it you see it kind of goes green there it's odd that it's green for disabled but I guess it's red for enabled so they probably make scenes and I can do that in the editor as well just by alt clicking on the break point the break one is currently configured to suspend and you can configure whether you want the breakpoint to suspend the entire JVM or just the current thread of execution you pretty much will always suspend the entire JVM I guess you might use the thread one if you're debugging something in production then you only wanted to debug a particular transaction then you wanted your rest of your application server to keep going something like that and and you can actually not suspend at all and you might ask you know what uses a break point that you don't stop at and what I'll show you in a little bit and there's a condition here as well so so what we could do is we can drag that break point down a line and then we'll add a condition here say HP so we're only going to stop we know that our bug is provoked just on for certain parts of our chess board so we can look that up and it doesn't stop and but when we start looking at b8 it does stop so their conditions are close your expression it's a it's a sort of arbitrary expression and here it's actually using local variables so you can use all the variables from your local context as you would expect and even much more complicated expressions here if you like see whatever and one thing to notice is that cursive will actually auto import order require things as it does in a normal editor so we can Auto impact that they import that there and so that is not required in there in your main file it doesn't actually touch your source code it's just kind of locally required and this little expression here so when we close the expression editor that's gone well it's stored with the with the expression so if we change the expression then that goes away but again Auto importing it again is very simple and it does the same for Java classes if you have a reference to a Java class and they're a little important okay so look at that so I mean it's a debugger we should probably so you can actually read those comments how I put here to explain kind of what I'm doing so right so when you're debugging Java code your code is quite static right so you write your Java code and then you execute it and you can place breakpoints and then why are you executing your code doesn't really move around and the same way it doesn't close you so IntelliJ in in sort of conjunction with the JDI when you put a breakpoint in the source line it maps that to the to the corresponding executable bytecode because at the end of the day you're really debugging the executable stuff you're debugging the bytecode itself right so you have to be much more careful of that and closure so here for example a breakpoint has little ticking it over here but if I delete this comment for example all of a sudden has a little X in it and that's because we've moved our source around so the bright the compiled bytecode no longer contains any executable code at the line where the breakpoint is because the breakpoint has been moved around by editing the source so if you actually debugging in a ripple and you're sending code to the ripple and you're you know you're adjusting code in the editor you do have to be quite careful to make sure that what the code being executed and your ripple still corresponds to what you have in your editor there's quite an easy mistake to make the easiest way to fix it of course is just to reload the code and the ripple and then so that recompile it and that means that the compiled code now once again corresponds to what we have an air editor so if you're better start debugging a namespace in the and the ripple I recommend loading the whole namespace first if you can but fortunately you do actually get some feedback there about about the fact that the breakpoint is no longer valid but if you just move up one line that will not be marked if there is actually executable code at that line but it's not the code you think it is and then you'll get extreme strangeness which you don't want so this being a debugger we should actually try and try and debug a bug and see so if we we do this say for some clearly absurd position whoops we're going to get an index out of bounds exception because it's going to calculate some position in our victor that doesn't exist so we can get the stack trace of there here which obviously on a normal monitor you can actually see and again this code here it's simple enough that you could just read it and trace through it and your head and figure out probably what the problem was but in a real program you're going to have a lot more stage it might be a lot deeper in your stack it's going to be nowhere near as obvious what's going on so what we'll do is we'll create an exception breakpoint so four index out of bounds exception and now when we do this it actually takes us to the point where the exceptions drawn so as soon as that exception thrown the JVM will break it'll stop the whole thing you can look here here on this tiny monitor it's a little bit difficult but you can see the stack trace you can see how you got to where the exception was thrown you can see the local variables and all the contexts leading out to it so it's quite easy to quite easy to figure out what's going on and that's probably the breakpoint type that I use the most when I'm debugging cursive often a problem will start with an exception so I just say stop us in this exception of throwing and then I'll go back and see see how how I got them okay so we'll look at another example of that and again we just hide this here this is another example from the joy of closure it's actually slightly modified so they have some examples about exception handling so they have a function here that accepts two parameters and just divides one by the other and then they therefore broken exception by dividing by zero and then they catch that exception and just print out something went wrong and then they have a second function that catches it and Andry throws the exception with an e X info with just with some information about the parameters that provoked the problem and then when they actually call that they printout received error and they print out the X data so you can see a bit more about what actually happened and then I just have a little driver function here to do that so again we can load it into our repor hopefully oh I just wish that I rippled in and so we can load that in Webster Network okay so we'll load that in we'll switch to the namespace and then when we when we run this sure enough something went wrong and then we get our information so it's throwing the exceptions that's catching them as printing out what you would expect so it's that one I mean this monitor is kind of annoying we'll just get rid of that what are you there sorry about this that's not working for me I'm gonna take this out of presentation mode which might make the text little sore our smaller sorry can you read that oh right still cool right so oh my god it's still doing it okay so so we'll do an arithmetic exception here and we'll do the same thing and sure enough it stops in numbers dot dot class and that's it so the numbers class is what cloture uses to do a lot of its arithmetic operations so it stops here and then we can run and we'll do it again for the second one and take us out so that's quite nice so we can do that and we can actually keep snipping from here as well so so one thing to notice is that I don't have the source for closure attached here so IntelliJ actually compiles the class and shows me where I am in what looks like Java and in fact this does come from Java but even if its closure sauce it'll be compiled into Java so you can sort of see more or less what's going on you don't have to actually be looking at the bytecode and then the latest version IntelliJ 14.1 you can actually debug decompile classes so if you're something you do have to source for you can actually place breakpoints in the decompile java and step through it for all your heckling needs so we can actually keep stepping from where we are and we can to the catch block and then once we're done with a catch block it takes us back to where that was cooled from because the same thing again we can step out it takes us into that catch block and then where this next exception is thrown and record and takes it to the catch block there as well so that's quite useful again you can sort of trace through from where an exception is actually caught to see what I see what's happening so one thing that I do quite a lot in cursive so one of the major subsystems in cursive is the indexing infrastructure so this generally gets run when IntelliJ starts up so it'll find any files that have that have changed from when the index is were actually cached and and will reindex them and it's a fairly complex thing so I quite often get bugs in it and these bugs are often exceptions and I want to have an exception breakpoint that catches it the problem is that if I just start a copy of IntelliJ opening the project that I know provokes the problem and I have maybe it's a generic exception that's thrown like a runtime exception or something like that something run class a runtime exception and its various subclasses are probably thrown and caught quite a few times in the IntelliJ platform while it's starting out and I don't want to be looking at all of those because they're not interesting so I can actually place a breakpoint here and I'm not going to suspend on it so this is like a breakpoint that does nothing right there's it doesn't stop it doesn't do anything but then I can look at the arithmetic exception here and I can say this breakpoint is not enabled until we've hit this other one so now when I do this we stop here but we've actually when we go back through the stack trace we've stopped at the second one so the first one didn't stop because the breakpoint was disabled until we hit that so you can actually use this so the conditions on your breakpoints you often use to delimit kind of the state of the program that you know causes your program so a certain set of parameters or part of the the actual state of your program you can do that and you can use these breakpoints to delimit the area of your program like the region of code that you're interested in which is which is very very powerful and I use that all the time when I'm because so you can do other things with these breakpoints that don't they don't do anything we can log a message here so now when we when we do this reason and so it'll just log a message saying this breakpoint was reached so you can put a little marker there to see if it's even getting to a particular part in your code if just knowing it got there is not enough you can actually log an evaluated expression yeah and again so this is like a sort of a fancy form of print l'm debugging and you might say well i just put a print then and reload my function right and that's fine if it's your code you own the code there's one problem with that when you're debugging which is that in modifying your function you're going to move your source lines around again so you get that problem we spoke about previously if you're not careful but also maybe you don't control the code maybe it's in a dependency maybe it's Java code like I quite often want to see what's going on in some Java code and I can't just put a print line in it and load it into the ripple so you can use these as sort of like a print than I could just put anywhere anytime and see what's going on and again it's a totally arbitrary closure expression you can use your locals you can use variables from estate static method calls whatever you want so this is an example from closure programming actually they have this is the game of life commerce game of life so they have a much more complex example of this it has a swing GUI and then they go through various iterations of that work so I've just got part of it here so put a breakpoint here so the other thing we can do when we're here is we can we can evaluate some expressions right and we can look at against our it's a bit annoying to see the local variables but we have some local variables there called X and Y and we can look at the board so they're using a different representation here they have a victor of victors to make a 6x6 board so you can see the different values in here so again you can sort of navigate down into it and see and we can so again these are totally arbitrary expressions and again because that's because of the representation you really want to be doing something like an exercise in our board so again it's totally totally our tree expression you can require whatever functions you need here you can you can pretty much do whatever you want so this is sort of like a ripple while was the the main ripple doesn't work at the moment because the JVM is totally Rosen right if you into something in the and the ripple it'll just sit there but you can use this evaluate expression it has a slightly more annoying interface than the ripple but it does also allow you to do things like drill down into data structures and things which is quite nice so that there are some interesting tricks with this so normally in in Java when you're evaluating an expression when you stopped at the debugger you have various things available to you you have the this object and you have your local variables and so we have more or less the same here except in closure you can't normally refer to this object there's no way to do that and Java you can always just refer to it so but we were actually evaluating expressions previously with with variables that are not in our local things so we also have variables under add this object we have two closed over variables so because we have some nested functions here this function refers to some variables that are outside at scope so the closure compiler has created a closure and has placed those variables in there and we can refer to those in our expressions so in our expressions we can refer to x and y new board board and but what's interesting is we can also refer to other variables here we can refer to the width and the height and these are actually right at the top of our stack here and if we look here they're actually not available in a local context at all they're not available and our local variables and they're not available in our closure and so what cursor does is it actually walks up the stack over here looking for where those local variables are found and then when it finds a stack entry with local variables matching what you're trying to use it will just check that that stack trace entry actually comes from somewhere within your top-level form here because it knows the file that's coming from in the line range and if it does then it knows that that's a local variable it's like I sort of potentially closed over variable and you don't normally have to think about this when you're programming in closure right and you just sort of you use your variables in here and then the closure compiler takes care of automatically closing over the variables that you need and crystal tries to do the same when you're evaluating the expressions so when you evaluate an expression here it tries to give you access to the to the variables all the variables that you would have available to you while you're while you're actually working in your closure code there are some cases where this doesn't work properly and you have to be a little bit careful so one case is if you have an anonymous function that you're debugging and that anonymous function is actually in the endless calling and this function here where it's contained it's actually returned on a lazy sequence so what will happen there is that the lazy sequence is not usually realized at the time it's returned it will be realized your function will be called at some later point when something else is realizing your lazy sequence your function will be called at that point and all this local context will no longer exist that's totally gone right it's just you you only have your local variables and your function and you have your whatever variable is the closure compiler closed over so then you'll get some weird message like variable W can't be found and that could be quite surprising if you don't understand what's going on and you get the same there if you create an anonymous function and you pass it to another thread it was obviously this local context is per thread so if you create an anonymous function and you pass it to P map or you pass it to an agent or you put it in an executor or you're working with swing and you put it on the ADT then when closure tries to when cursive tries to walk up the stack to find these local variables it won't find them and you will probably be surprised if you don't understand what's going on so you do it to be a little bit careful about there so this is great right it's a fantastic tool and I can see you all forming orderly queues here to give me money orderly and yet highly concurrent queues obviously but there are there are definitely some tricks you have to be quite careful with so the first one the first obvious thing is just that that there's a lot I would say the main problem with the debugger at the moment is there's a lot of leakage of the implementation into the debugger and this is because you're actually debugging the executable code so it's easy when you're looking at your editor to think that you're debugging your source code but you're not you're debugging the executable code and they're quite different so in Java there's more of a mapping between the source code and the executable and Clojure there's a lot of different ways that there can I open so firstly the most obvious one is that you can see a lot of like Java stuff and here there's lots of ugly mangled names and your variables have lowercase names locate these underscores and them rather than dashes that's actually an intelligence oh this is because when they split IntelliJ into the platform and the Java part the debugger did not get fully migrated across so the debugger is still somewhat legacy code and they've actually over the last couple of major release has been migrating their to the generic framework that they used to implement debuggers for Ruby and Python and things like that so I'm optimistic that in the next major release of IntelliJ I'll actually be able to prettify all of this and will look much nicer for everyone's eyes but there are also there's quite a lot of the implementation of closure leaks through here as well and so we'll look at some examples of them so if we go back to our original example here and switch this namespace execute this again now if I step over this here ice tip and I get some local variable appears here and it doesn't go to the next line what's going on and I step here again this is because to understand what's going on there we just need to look at the macro expansion of this so this is what the structuring actually looks like right when if you look behind the scenes it takes the pause which is the original variable and then it picks the pieces out the D structured pieces within and vêoc now you can see that in your source code but these are actually two different executable things so the macro expansion is creating more executable functions than you had in your original line of code and that so there is it's a general problem with a lot of these debugging tools which are line oriented so the JDI is very very heavily line oriented rather an expression oriented which you would really want so sometimes this is quite obvious so if you have a line of cloture code and you're sort of calling various functions and we can see a simple example here like there's at least two executable things on this line right and dicks and either call to index and the call to board so sometimes that's very obvious but sometimes it's not so obvious generally because of macro expansion so you do have to be a little bit careful you have to sometimes understand a little bit about what's going on behind the scenes enclosure to be able to understand what the debugger is doing it's not really a serious problem you're just but if you have a more complicated destructuring expression here you can easily end up with ten expressions on their line so if you're just stepping over there's not really a problem but if you're stepping into things that can be more of an issue here's there's some other craziness here I can put a breakpoint here and it stops at your breakpoint when you're loading your namespace in to the ripple and if you're from coming from a Java world you're like what is going on and that is because the execution model the compilation model and closure is very very different so when it loads a namespace mm-hmm what it's actually doing goes through it reads every top-level form one by one it compiles there and intervals it right so the loading the namespace is actually executing your code so you do have to be you do have to be quite careful about that that can be very surprising and we look at another example here so a lot of people ask me if you can use this to debug web applications and you can of course it's just executable code all of it so you think hey I'll put a breakpoint here because I want to see what happens when I call this particular URL and again when I'm loading that namespace it hits the breakpoint even though I'm not the breakpoint isn't on a top-level form and again this is the this is basically the same problem difference here as a macro we expand it out and it turns out to be this diff thing here which and these macros compile out into more executable code and you can see here from that single line of source code there's a ton of executable code in here so you do have to be quite careful with that and you need some sort of understanding of what the code you're actually using right so and the other big problem I think is performance so this is a little glimpse into the eye of madness here clj 1330 so the JD I really wants to know the class that that you're working with and it would really like you to be able to say for this particular line of source what is the class that's being executed at that line and then so when you look at this you realize there's really no way you can actually predict that so there are all these different cases down here on the left so maybe you think oh well you know I'll just have like a big Condor something to figure out what the cases are and and match them to this thing on the right but of course again it could be macros right you can have any macro form that expands to any one of these forms and so there's really no way unfortunately to predict for a particular line of Clojure source what the class name is that's being executed on that line and JDO really hates that so unfortunately JDI will often ask me that and and I pretty much have to give it back all the classes for the current namespace and say could be under any one of these I can't help you basically so when you're actually calling out to the JD I often it allow you to use a filter they have a hilarious thing in the documentation where they talk about restricted regular expressions and that turns out to be the exact class name star name or name star so when they say restricted regular expressions are at least half right right now it's certainly restricted but it's even worse than that because sometimes you actually can't use those filters and so in those cases my only option is to go out to the debug JVM get back every single class and the JVM and filter them out get all the classes from that namespace and then give those back and say could be any one of these can't help you so the performance debugging closure code sometimes I haven't actually fully identified when these different operations are used so sometimes debugging the closure code can be slower than debugging Java would be so I guess I kind of felt like I've spent a lot of this talk almost apologizing for the experience of debugging closure code but done did they put you off it's an awesome tool I use this every day it I couldn't do my work without it basically for the sort of work that I do and lots of other people cursive users are using it it's really it's it is a really fantastic tool I wish I had more time I could talk for two hours just about the debugger and and demo all the stuff there are watch expressions you put an expression there and as you're stepping through your code it will show you how the values evolve you can put field watch points so it will break when a field is accessed either read or written you can stop on a break when a method is called this is kind of annoying to use in closure because again you're talking about the man's name so so these are not I don't actually use it very much you can group your breakpoints for your really complex debugging needs you can have temporary breakpoints you can look at three dumps you can analyze for three there's all sorts of stuff there and yeah it's a very very sophisticated tool because again JetBrains been doing this for years right I'm gonna be adding some more stuff to this these first two should be coming pretty soon actually so instance marking this is actually in the Java debugger so you can when you have something in your local variables view you can actually mark a particular object instance and give it a label and then later you can refer to that in your expression so you can actually have a watch point for a particular object instance and the JVM even if it's in some stack frame somewhere for some other thread than the thread you're looking at so you can refer to that anywhere you can refer to and breakpoint conditions and watch points it's really really useful so somebody asked me the other day how they were debugging a concurrency problem and they wanted to know they wanted to be able to debug promise that was in a local context and another thread this will allow allow you to do that so that's hopefully coming and I think in the next release I'm going to add their smarts Tippin also helps when you have this problem with a lot of executable code on a single line so when you step into a line that has a bunch of different executable code on it cursive will actually work out what the potential calls you might be making there are and it will present a little drop-down list so you can say actually want to jump into this function here again the ripple is fro that the ripple is frozen while you're debugging I actually but I actually think you should be able to make it work by by using the expression evaluation on the debug to JVM so I want to get that going I think there's a lot of scope for specific closure breakpoints as well so you might say I'd like to break I'd like to break when this atom or if are updated I'd like to break when this promise has a his result delivered to it make the method break ones easier to use again by probably undone geing the names or something like that I'd like to try and do something about the performance I don't know how much I'm at you gonna be able to do about that but I'll see what I can do and I'm also going to be developing a clojurescript debugger so I've been talking to David Nolan about this so you'll have the same sort of interface and you'll be able to debug your clojurescript code right from the IDE and a browser and nodejs and it's like that with react native you like to be able to debug right on your device which should be pretty cool and everything in the in the IDE will be displayed as clojurescript objects not actually as closure as Java as JavaScript objects so that's it thank you very much if you have questions come talk to me afterwards I'd love to hear from you