 On today's Visual Studio Toolbox, Steve Dower is going to show us how you can use both C++ and Python in the same project. Cool stuff. Hi, welcome to Visual Studio Toolbox. I'm your host, Robert Green, and joining me today is Steve Dower. Hey, Steve. Hey, how you doing? Welcome back on the show. Thank you. It's been a while. We're going to talk about how Visual Studio makes it really easy for you to do both Python and C in the same project, such as a game. Such as a game engine. Yeah. So this dancing guy in the background, his name's Sinbad and he's joining us on the show as well today. He's actually one of the samples that comes with a game engine called Ogre 3D. So it's an open-source engine written in C++. Really easy to use as I can now vouch for because I picked it up and made a demo. You made dancing Ogres. I did dancing. So this came as part of the sample. What I've actually changed for this from the usual is normally you'd make him run around with the keyboard and you've got different commands and stuff. In this case, instead of doing that, I've taken the sample and dropped in a Python runtime, and so there's a Python script controlling what he does. So let's start with this. So before we see how, and let's talk about who, why is this a popular scenario? Are there lots and lots of people doing both C++ and Python in the same app? Yeah. So Cpython is the main implementation of Python that most people use. They don't really think about it, but it is the most popular one. And it's written in C. So while most people kind of sit in the Python language, you've always got the option to extend that with a module written in C. So if you want some native code, run something faster, access the operating system, you can write some C code and call it from Python. And you can go the other way and you can take a C app and load Python into it and then call from the app into Python. So C++, you don't see a lot of scriptable programs, ways of letting your users extend it by writing scripting code because it's a lot of work. Using Python and in fact using a library which I'll also show called PyBind 11, it gets really easy to take any native code and expose that to Python in a way that you can then say, hey users, go ahead, extend this. And that's a really common scenario. Everything from business rules, if you start putting them in Python instead of C, game scripts. We see a lot, Lua's also popular for this kind of thing. And plenty of ways where you don't want to bake everything into the code or you don't want to have to regularly make changes and rebuild, redeploy. Okay, cool. So just to prove that this is in fact a Python script, let me, I'll tab back into the source. This is my little script here. At the moment he's dancing and then standing for a little bit as we saw. If I take these and uncomment the rest of the script, I'll just hit save and I'll switch back here and hit the reload key. So that's just loaded the script and now he's changed. Yeah. And he's going to do different things because the script has changed. I didn't have to close the program. I imagine if I'd written that in C++, it's close the program, change the code, save, compile, compile, compile, compile, compile. Link, link, link. And then start it all again from scratch. I could just go in and make a really quick change and I can do it again, take out the dancing. If I want, reload the script and now he's not going to dance anymore because I've just made that change. Right. So it's a really neat way to either let users who are not the developers change what it does or even just in your own development, get through stuff really quick without having to go through those long cycles. Once the core of the app is there and the logic is what you're working on. Cool. So let's dig in a little bit deeper and see exactly what's going on here. First thing I'm going to do is set a breakpoint here in this bit of code. This is my function that gets called by the game engine every single frame. And it's basically, it's waiting for a bit. We let each step run for a few seconds, as you can see there. But when it comes up to change, we're going to grab the next step and then execute that, which is going to go through this code. This is all still Python code. And if I look at the locals, then the command we're using here is jump. So we're about to start jumping. That command is going to call inter-c. And it's actually going to show up here, which means I'll just save us a little bit of time and step to the breakpoint on that. Now we hit c. What does Visual Studio give you in this place? You'll see the call stack here. If you've debugged in Visual Studio before, then you're familiar with the call stack, debugging, everything like that. What we have here is something really neat. And that is mixed Python and C++ debugging. Typically, if you have one language at a time, you only work in one language. Maybe it bounces between C or C++. In this case, we've enabled Python. And as you can see, we can step around through them. We can inspect all the variables, just like you would in either debugging Python or debugging C. This is a really powerful way to see exactly what your code's doing. And check the various things out. And obviously, I can keep stepping. I can see autos and locals filling up. If I jump all the way back out to this level, we can see one really short line of code. And this code's doing a whole lot of work that you really can't see. So this MAO module is a PyBind 11 module. PyBind 11 is this really nice library that uses originally C++ 11 features. But now, 14 and 17 features as well, to very quickly take C++ functions and expose them into Python. So normally, there's a whole lot of work. You've got to convert types. You've got to go, oh, this is a float that's turned into a Python float. This object has some methods. We need to make those methods available in Python. Normally, a whole lot of code. Most people don't want to touch it because it gets very scary very quickly. And where did that come from? So PyBind 11 is a community project. It's an open source project. I have done nothing special with it. I just grabbed it off GitHub. I did write this module. So this is just a header file that is defining an embedded module. It's called Ogre. And then I've used the functionality here to expose a whole lot of my C classes or C++ classes along with their members. And it is really simple. So that jump command that we went into before, this is the definition. It's called jump. And this is the C function, jump. That's all it takes. It figures out what the return type is, what the argument types are, does all the conversions. Really, really quick, really, really simple. So then when I call it from here, in fact, let's look at dance, I get the dance method. And that is going to go through where we define dance here, call this, and then it will end up in the C code. I'll stop here. Because one of the things that you need to be doing all of this is to actually install some of the extra stuff. Right, and you get this. Is this features a Visual Studio? Is it stuff you install? When did it appear? Yeah, so I've got up the Visual Studio Installer as of the latest release, 15.7. It's been in for a little while longer than that, so if you're on an older version, you may have had it as well. But obviously, we like people to be running the latest version with all the latest fixes. And we'll see the Python development workload here. And over here on the right-hand side is Python native development tools. This is typically a very big install because it brings down all the C++ stuff you need as well, including the compilers. But once you get the Python workload and this item, you get a whole lot of cool functionality for doing anything between Python and C. So we really recommend it. One of the things you get out of this is this Python native debugging option, which you don't normally see for a clean install. But when you pick that option, we'll show that up. And this is how we're giving you the mixed Python and C mode. It's not the default because we can't assume that it's going to be there. But we want to make that available. And so that's how you get it. You'll also get all the compilers. So a lot of people who are, even if they're just using Python, will try and install packages and they may fail because they need a compiler. That option will give you that compiler. The developer team that works on Cpython, which I'm also a member of, when they want to build on Windows, they need all those tools. And so the instructions for contributing to Cpython are now go and tick this box and you'll get everything you need to build even Python itself. So whatever you want to be doing with Python and C, that's the option to go and get is the Python native development tools. And then the Py11, you said was out on GitHub. Is it a NuGet package or just on GitHub? I didn't find a NuGet package myself. I pulled it down as a submodule into my repo, which I'll give a link to this example later on so people can go try it. It's header files. It's just header files. You include a couple of header files and they do all the magic when your code's running. I didn't actually show it when we were running before but if I start running again, let that start up and throw another break point back in here. I don't think he's dancing right now. So now when he starts to dance, we'll break in and we'll have a look at the call stack. What I've actually, I've also used a semi-secret C++ feature here to make things a little nicer. You'll see these external code markings here, which are things you don't have to worry about normally, but you can show them anyway. You can right-click and show external code. And when I do that, you'll see that PiBind 11 items are showing up there. Now I say it's a semi-secret feature because I added a file onto my machine to say hide PiBind 11 for me because I'm not interested in it right now. Those are also in the repo that I'll get to at the end. That's native just my code extensions. There is a very helpful documentation page and basically no one knows about it. But there's your secret C++ debugger feature for the day. You can hide whatever code you don't want to see by using that and just make it external code. So, but how do we help the developer here? Python developers who are looking at this are probably looking at this function definition and saying, oh, this looks not like Python, this looks more like TypeScript, what's going on here. Recent versions of Python have introduced type hints. So it's kind of like TypeScript added type hints to JavaScript, slightly different. It looks similar, really, it's just a help. It's kind of like documentation for types. But it lets us do things like say character is of type character controller. Normally we don't need this because somewhere in your code your call on frame and we can figure out what you've passed in so we know what IntelliSense to give you because when you type character, obviously you want to see character and you want to see everything that can do. In this case, no one calls on frame. It's coming from C code. It's coming from here, that's where we call it and we don't know exactly what's being passed in. So we've used a type hint here to specify that. Okay. So that's a hint so that you can get IntelliSense at design time. That's exactly what it is. You can also use some tools to do static type checking as well. So there's a tool called MyPy, which if you're in a Python project will help you run over your code. That can go through and validate all the type hints and make sure that you're not passing in something of one type when another type is expected. It will give you all the warnings. It will help you resolve those. And say Python feature, you said the type hints. Yes, the type hints is a Python feature. The tooling for doing useful things with them like we are here is separate from Python. Python has made it consistent. It's made a consistent way to say, these are what the types are. And then all the tools can jump in and do what they want. So if you then open that Python file in a different editor, if it's supported the type hints who would know what to do with it, otherwise it might not know what that meant. Exactly. And in this case, I've actually had to do something tricky because this type character controller is actually defined over here in C code. And there's no Python code to figure out what it should be. So I've pulled a couple of little tricks here that we've enabled in some of the more recent versions of Visual Studio to make this work. If I go to definition on this, then we'll see what it actually is. It's here in this file. And there's not a lot going on here. So this is fairly new and is a little bit unusual. It's called a type stub file. So it looks like regular Python code. We have all the definitions, type hints everywhere. All the bodies are just dot, dot, dot, because we don't care what they are. But what this, and if you look up here, you'll see the file name is ogre.pyi instead of .py. Normally it would be py. This is just the type stubs. This has nothing but information for us to use when doing IntelliSense. And I've written out a whole lot of these by hand, but it means that when I come back to my original code and I import from ogre, Visual Studio is gonna find that file and use it. Normally if I import something that doesn't exist, so if I import a bigger ogre, that's gonna come up with a warning saying, oh, we couldn't find that. In the same way that without this pyi file, we wouldn't have found ogre. But because we've found that, we can give you all the information and it's fully controllable, which means that if you're in the position of writing some extension stuff for Python and then sharing it with your development team, you can also give them this file to make sure that they have a good development experience and they don't have to miss out. And of course, type hints don't have to go everywhere. We still do all the same thing we've always done in Visual Studio to figure out what types are what. So you can see command here is coming from a script. We know all the possible commands because we've seen them in the list, which means we know all the possible execute methods. I can go to definition on this and we'll give you all the possibilities. And when I get into here, you'll see that character doesn't have a type hint on this one. And yet if I type character and dot through, we still know everything that's in it. So we're still doing all the magical type inferencing that goes on everywhere. But we're also giving it the option when there's a place where we can't possibly figure out what's going on because as far as Python's concerned, no one ever calls that function. It's coming from somewhere inside a native binary. We have that escape hatch. And so you can specify what type is going to be there because sometimes you know better than the machine. Those of us who build the machine don't like to admit that but sometimes the developer knows best. And so you have the option to specify that where it's needed and the rest of the time you can rely on us to flow that information through and give you the great experience you've always had. Cool, very cool. Does Visual Studio code have similar capabilities, do you know? Visual Studio Code has a lot of similarities. Unfortunately when it comes to the C++ Python side, that's very much just a Visual Studio thing. We certainly have had people ask for it. Can you please bring this to Visual Studio Code so I don't have to start using Windows? And unfortunately there's a whole lot of reasons that that's really hard for us to do. Or rather there's a whole lot of reasons that's really easy for us to do it on Windows. Right. And so we've done that. But at the same time we've had people come to us and say, I was happy to switch to Windows to use this. And you have no idea how good that feels. Cool. So just to give people something to follow up on. All right, we'll have all of these in the show notes but we'll just be putting them here. These are the repository with the sample and hopefully good enough instructions for anyone to follow along. There's also just a couple of links for all of our Python stuff at Microsoft, all the things that my team and other teams are working on. And our blog which will have a blog related to this go out when this video is out. So that'll be there at the same time to go check that out and try out our other things, let us know what you need, how we can help you be a more efficient Python developer. Awesome, cool stuff. Thanks for coming on and showing us that. All right, hope you enjoyed that and that you give it a shot and we will see you next time on Visual Studio Toolbox.