Transcription
Over the years, I've learned a lot of programming languages. However, one thing I can't be bothered to do is read through those enormous books— you know, the ones that go from page 1 to 800, telling you everything about a programming language.
Yet, I've learned Ruby, C, C++, Java, Object Pascal, Modula-2, and many more programming languages. I've been programming since the 1980s, and I've had plenty of time to figure out an effective way to learn a language. That's what this video is about.
What I don't do is read huge manuals from page one to page 800. I don't do hundreds and hundreds of little programming exercises. I know that some programmers, when I've taught courses on programming, get very wound up and obsessed with solving problems and having exercises to do. Exercises have their place and can be useful for some things, but that's not my approach to learning a new language.
To learn a new language quickly and effectively, pick a project and get programming. It's as simple as that. I'll show you what I mean. As always, if you've followed some of my other tutorials, you'll probably guess the project I'm going to pick: it's going to be a simple adventure game.
Adventure games are great because they involve all sorts of things: string handling, class libraries, file handling—just about everything, really. But if you don't like adventure games, pick something else. It could be a utility, or I don't know, I really have no idea what interests you, but find something that you're interested in and start learning that way.
I'll show you how I do this. I'm going to show you how I started learning the D language. I picked D because it's a fairly well-established language, but probably one that most people are not familiar with. I've never really programmed in D before. I've been aware of it over the years, but I've had to learn from scratch.
So, I'm going to show you how I got from no knowledge of D to writing a simple adventure game in about three hours. Let's see how I got started.
Clearly, the first thing you have to do when learning a new language is install the compiler or interpreter. That is the thing that's going to run the language for you. For D, I've gone to the programming website and found the download page. There are lots of downloads here for Windows and various versions of Linux and macOS.
I'm programming on Windows, and I've decided to use Visual Studio. There is a Visual Studio plugin called Visual D that I can download. It includes the D compiler, so I don't have to do more than one step. But if you're using other operating systems, then Visual Studio Code is quite well supported. It takes a bit more setup, and unless you're very familiar with it, it'll take a bit of learning, which is why I'm really more comfortable with Visual Studio.
Then I need some reference material. The D site has fairly comprehensive documentation for the language and its libraries. As an added extra, there are also various tools, editors, tutorials, and books. I'm going to use this online book, or you can also get a PDF version, so I can dip in when I need some extra help.
Having got my D IDE up and running—this is the one that's in Visual Studio—the next thing to do is to start writing something. So, I start a project. I can search in Visual Studio for a particular language. If you're using another IDE or text editor, of course, this step is going to be different.
I just select an application and see what happens. D application? I'll just use all the defaults. Now it's prompting me for a console. Yeah, I'll go for console. This is the standard reference D compiler. Okay, I'll accept that. Finish. Let's see what happens.
So, it's gone away and generated something. I can see there's a dprogram file here. Let's have a look at what's in it. Ah, so it's created a simple file for me. Let me try running that and see if it works.
So, it's compiling it, and ah, it popped down again. I need to put a breakpoint. A breakpoint will stop it from exiting, I hope. Let me look at it. Okay, so "Hello D World." That looks okay. What do I do next?
Let's stop this back in here. Well, let's see if I can guess my way through it. I've got some experience with C and C-like languages. Let's try an array of chars—a string, in other words. It turns out that D has more than one way of doing strings, but I'm going to stick with this char array. I'll call it s.
So, this is me guessing my way through the language so far. It works okay. So, let's have a look. I've got "writeln." Well, let's see if there's a "readln." "Readln" is the same name. I happen to know these from Pascal; these are standard names in Pascal. Let's see if this works in D.
It's looking good so far; the error squiggly is gone. So, let's see if I can append that to this string. Normally, that's done with a plus. Ah, it's not liking that. So, that's where I've had to resort to the documentation.
This is the first time when I was learning this that I had to resort to the documentation. It tells me—I'll save you the time; I won't show you it all now—but you just look it up in the online documentation, and it says that tilde is the way of appending one string to another.
Instead of putting a breakpoint this time, I'm going to put "readln." Just like Pascal, it also lets me omit the empty brackets if I wish to. I just found that again by trial and error—no special magic on this.
So, let's see what happens. Okay, so enter my name. It should read that, assign it to the string s, and display the string. It's paused at the end because of that final "readln" I put. It's waiting to read the final line. It'll do that when I press enter. And there you go.
So, that was my first program. All of that was done with guesswork, apart from this one thing I had to look at—the tilde—to find out how to append a string.
So, that was my first five minutes. I said that it took about three hours. Let's see what I accomplished in the first hour.
Well, I'm trying here to create a class. That's a class that's going to define an object. When I've looked at other D tutorials, they leave classes and object orientation until the later chapters. You might be well into the tutorial before you even look at it.
Well, I decided that I need to find out how to use this quite quickly. So again, mostly this is guesswork from my knowledge of other C-like languages, like C and Java, for example. I created a class called "Thing."
D does have a string data type, so I gave it a name field. I had to look up how to create a constructor. It's using this keyword, and then you pass it arguments. Here, the string argument is used to initialize the name field. I wanted the name itself, the name field, to be private, so it's encapsulated, and the data is hidden.
To have accessors, the way that I chose to do it was to have accessors called "name." Now, even though these two methods have the same names, D differentiates between them because they've got different argument lists. So, I can assign a string using this one, and I can return a string using that one.
Now, I then descended another class from "Thing." This again was guesswork because I've come across various different syntaxes for creating lines of descent. It turns out that indeed this colon is put between the new name and the ancestor class name.
But again, if you wanted to, you know, if you couldn't figure that out, just simply looking it up in some documentation will explain that very quickly. Now, the "Room" inherits the name from the "Thing" class and adds these integers: north, south, west, east. Those are the exits to other rooms.
Then this is its constructor. It takes all those arguments and calls "super." Again, I guessed this from experience with other languages. It calls the superclass, passing to it a name, and then it initializes these arguments.
Now down here, I just messed about. I mean, this code is all over the place, really. But that's a really important stage when you're learning a language: just mess about. It doesn't matter if you mess things up. In fact, you should, because you're really trying to find your way around the language.
So, I've created a new "Thing." I've used "writeln," which I've done before, and then I've created a new room. Now I've written this prompt character to read the string that the user enters.
I created a new "Thing." Now, s.dodap—this is to do with how strings are handled. The difference between strings and character arrays is that there is a distinction made. So, this string has been read here, and I need it to be duplicated as a character array. I had to look that up; that was one thing that I wouldn't just guess.
I did look that up, and so this is the kind of process I go through when I'm messing around. I hit a problem; that's the stage at which I have to go to the documentation to look things up.
I discovered that, as expected, I can pass an argument like this. An alternative syntax I just found through messing around and trying it out is to use it like a property in C, where you use this like a variable, even though it's actually a method, and assign the string, the single argument, to it.
The rest, I think, is fairly straightforward. Oh, I wanted to display the integer on the north side. Again, I had to look up how to convert an integer into a string representation, and I found that this is the way to do it: two exclamation marks and string.
In order to do that, I had to import std.com, so again, that was something I had to look up. Is there anything else that needs explaining here? I don't think so.
Oh yes, there is one thing. I tried to make this private. Again, these are things I had to look at: how do you make sections of a class private or public? By putting "private:" I can declare a section of private variables here, and then these accessor methods are public.
However, I discovered that I can actually, if I wanted, make my private variables underscore name. That shouldn't be available if it's private, should it? So, I should have an error there, I'm expecting. But apparently not.
So again, that's something I had to look up: why is that privacy not being observed? It turns out that in D, even if something is private in a class, if it's all in the shared module—that's this single code file in this case—then it will be public, which is not what I want.
So, I had to find out next how to create a module. Again, that's something I looked up in documentation. Here, I would say in my first guess, maybe 80% of the code, and I ran into a few problems, which I've mentioned. That's when I had to look up the documentation.
Right, so this is my rewritten version. Here, I've added a module to hold my "Thing" and "Room" class. In Visual Studio, that's done by right-clicking the project and then clicking "Add" to add a new item. Obviously, that's going to be different in other editors or IDEs.
You can see I've just created a module called "MyClasses," given it the name up here, and it's in a file called "MyClasses.d." This is just the same code that I had in the previous version. I've still got "string underscore name" marked as private.
Now, if I go into the main file—the file that starts the program—that just creates a room and writes this prompt here. It says, "You are in," etc. The difference here is if I try to access that private field now, I get this squiggly. It says that there's no property "underscore name."
So, that is how I've enforced the privacy—just by creating a new module and importing that module.
Okay, so after that experimentation, I think I'm ready to start writing the very simplest possible adventure game. Here, I want a map containing four rooms. I've already defined the room object, as I've shown.
The "pause" integer variable defines the player's position, which starts off at zero. I've drawn out this little map, so r0 is the name of the first room. It goes east to room one (R1), south to room two, and that goes east to room three. There are no exits in the other directions.
I've then created the rooms. You can see the four rooms down here, and I've added them to an array. So, I've defined a room array called "map" to contain four rooms, and I've just added them one by one.
All of this has been done with guesswork because I've used arrays in other languages. If you've used C, Java, or some other C-like language, you can probably make a good guess at how to do this. I might have made a few mistakes along the way, but it was fairly simple to rectify.
Then I've just written this "moveTo" method. It takes a number, and that's the number of the room to be moved to. If it's minus one, that means no exit in that direction. Well, if it's minus one, I just display "no exit." Otherwise, it updates the player's position—that's the "pause" variable—to the new room number, and it writes, "You have moved into," and then it indexes into the map and gets the name of the room at that position.
Then there's my main function down here. That's what executes when the program runs. This is all fairly straightforward. I've got "exit" as an integer.
Oh, first of all, it calls "init." So, where is that? That's this method—that's the method that first creates the rooms and the map.
Okay, so it calls "init," then it writes that you are in—well, it's room zero because "pause" starts off as zero at the start of the game. Then I've got this "do while" loop. Again, I looked up loops in the documentation, but I was guessing there would be something like "do while," as that's a common sort of loop.
So, that executes the loop while this condition is true, and the condition is that the player has not entered "Q," the string "Q," to exit. So, not equals—that's again guessed from my knowledge of other C-like languages.
The "switch case" is very similar to other C-like languages. It's just a multiple choice. So, if the player enters the string that's read in from the command prompt up here, if the player enters that string and it's the string "n," then I find the exit at the north position in the room.
The room is the map object at the current position, and it's the same for south, west, east, and the default is "no exit." So, that should all work in principle. Let's see if it does.
So, south should go to—oh, there should have been a room there on east. I can't even use quit. There is something wrong with my code.
This is my other secret weapon. Before I go on, I should say that when I say I'm looking things up, I've got online documentation that I refer to, and I'm going to be referring to that shortly because my assumption is that there is something wrong with the way that I've read this string.
The string is not being recognized as "n." It's not matching this and so on. So, let's see what's wrong. I'll do it again. So, let's enter "s." Now that should match the string "s." But let's have a look at what "s" is.
Looks like "s." Ah, but if I expand it using the debugger by pressing that arrow, I can see there are two characters: there's an "S" followed by the value 10. That's an ASCII code 10, which is a line feed, not a carriage return, which is 13.
When I'm expecting it to match "s" down here, let me put another breakpoint down here. I'm expecting it to match "s." It doesn't because I'm testing that the string is one character long—that's just a single "s."
Back to my documentation. Okay, so this is where I start looking things up. I've got this "Programming in D" reference here, and I'm looking for something to trim off. In many languages, it's called "trim." I tried that, and it didn't work.
So, I've gone to the documentation to see if I can find something else, and this is what I find: in D, the function that strips off the non-printing characters, like spaces and carriage returns and line feeds, is called "strip." I assign it back to a variable, as shown in this documentation.
So, that's all the documentation I looked up to get this to work. Let's try that. So, according to this documentation, I should be able to call "s equals strip(s)." It seems happy with that.
One other thing I've had to do, by the way—again, this is where you look in the documentation—is I've had to import "std.string" to get this to work. Let's see if that works.
Right, this time the breakpoint is hit. Let's have a look at what "s" is. Yeah, so this got rid of the rogue character. Continue, and it's hit the case statement. But I'm expecting it to continue.
Let's get rid of all these breakpoints now so I can just continue watching the running program. Okay, so yes, I've moved into a new room. East—there should be another room, and there is. East again—should be no exit, and there is.
I can move around the game by entering the directions, and "Q" should quit because that's the test statement down here—the exits from this loop.
So, that's my first—I would say about three hours—from knowing no D at all to writing a very simple object-oriented adventure game. So, I'm pretty pleased with that.
That, in short, is how I go about learning a new language. Now, as I said, this has been about my approach to learning a new language. It's not a tutorial on D. Experienced D programmers will have much more effective and efficient ways of programming than I used in this video because these are just my first few hours learning the language.
So, whether you're learning D, Rust, Java, C, C++, or whatever you're learning, what I really want to get across is a way of starting to learn that language without getting bogged down with thinking you've got to read every single chapter in order in some impenetrably long book or solve hundreds and hundreds of exercises.
Anyway, I hope that's given you an insight into how I approach it, and maybe you can take something useful from this video. If you liked this video, give it a thumbs up. To make sure you don't miss any of my other videos, be sure to subscribe to my channel, ring the bell, and I'll see you again soon with something different.