Wave's~ BlitzMax Tutorial for NG | ~ November, 2015 ~ Version 11
Beginners guide to BlitzMax |
Abstract and Final
If you have an Abstract Type you'll be unable to create a new instance of that type. Which means it will be almost useless, or will it? You can still have functions and Globals and Fields in it. But you'll never be able to access those fields, except if you extend that type. The reason for abstract types is so that the user (which is a programmer using your type, including you) won't by mistake create a new instance of it. Vehicle is a good example. You cannot create a new Vehicle. Why you say. Because how would I draw a vehicle? As a car, a truck or a helicopter? Vehicle is abstract. This does not stop me from creating a car or a truck or anything extending Vehicle. The only thing you can't create an instance of is the abstract Type itself, Vehicle. But isn't car a Vehicle? Yes it is, but Car is not abstract so therefore you can both Draw and Create cars which are vehicles =) Let's say I want all Vehicles to have a method called create, so that all vehicles I use will be creatable (like a common interface for all vehicle objects). In this case I can make an abstract method, which will do nothing except giving a compile error if someone tries to make an extended vehicle (like Car or Bus) without a method called create. Finally instead of abstract disallows users to extend a type, let's say I don't want people extending my Car, if they try too they'll receive a compile error telling them they can't because it's final. You can also set methods as final which will disallow people from overriding them.
LinkedLists Lists of Objects
The default list in B-max is called TList . To help you better understand lists and for you to use them well I'll try to explain how they work. When you first create a new list it comes empty. Next you may add an object to it. (For this example Ship). The Ship is now the first and last object in the list. If we add another object we have a choice, to either add it to the beginning or end of the list. For each object you add to the list you add a link to the list. The Link contains three fields: 1) The Object you added to the List 2) A Link to the Next Link 3) A Link to the Previous Link. In this way it is possible to loop thru the list because each link is connected to another link. Like a long chain. The number of links depends on the number of objects. You never need to use the Link by yourself, BlitzMax does that for you with methods and functions like AddLast( Object ) or RemoveLast().
Put this code in a new file and test it, I'm going to extend it later.
Type TShip Field Name$,Score End Type 'Create some Ships '__________________________ Global Ship:TShip Ship = New TShip Ship.Name = "My First Ship" Ship.Score = 11 Global Ship2:TShip Ship2 = New TShip Ship2.Name = "My 2nd Ship " Ship2.Score = 3 Global Ship3:TShip Ship3 = New TShip Ship3.Name = "The 3rd Ship " Ship3.Score = 9 '___________________________ Global MyList:TList 'Define the List MyList = CreateList() 'Create a New List MyList.AddFirst(Ship) 'Add Object to List 'Now you could add to the top of the list 'MyList.AddFirst() 'Or add to the bottom MyList.AddLast(Ship2) MyList.AddLast(Ship3) For Local S:TShip = EachIn MyList Print "Name: "+S.Name+" Score:"+S.Score Next 'How many objects in the List? Print "Links/Objects in the List: "+MyList.Count()
So far there is nothing new, this was just the basics. We have encountered a problem that came from the use of lists. If your program has a place where it loops through a list that does not exist, you'll receive a runtime error. The solution is simply to put an if statement around your For.. Eachin Loop. You could also make sure you create the list before the loop (no matter what). Make sure you don't skip CreateList() or New Tlist. If you on the other hand have a list you want to clear you can remove all objects from the list using MyList.Clear(). That will clear the list but not delete it. An object exists as long as any variable is pointing to it. In the previous example the first-ship had two links. First the Global variable Ship:TShip and second the Link in the List. So to delete this ship you first have to erase the global: Ship = null. Second you have to delete the first ship in the list. (This is easy because it is at the top of the list). Simply go MyList.RemoveFirst(). If you do that there will be no way to retrieve the Name$ and the Score of this ship, therefore it will get deleted by BMax at the next Flushmem (you should have Flushmem once in your mainloop). MyList is of the TList-Type (or a TList-Object). RemoveFirst(), Clear() and most other commands are methods in TList. I guess you already knew that, but just to be sure. A TList can contain any object, just like an array of objects. Arrays and Lists share many characteristics.
Add these lines to the previous example, just below MyList.AddLast(Ship3)
MyList.AddFirst("A String is also an object") MyList.AddLast("This is now the last object")
If you run the program you'll see only the Ships being displayed. But the number of Objects in the list is five!
Add this:
For Local Str$ = EachIn MyList Print "String: "+Str Next
The Eachin-Loop only loops through the objects of the specified type found in the list. First I looped each Ship in MyList, now I Loop Each String in MyList. The actual List looks something like this now: "A String is also an Object" - Ship - Ship2 - Ship3 - "This is now the last Object" Let's say I want to print the Strings and the names of the Ships in the correct order, how to do that? It's quite simple yet a little more complicated than before. What you do is loop all Objects in MyList. Like this:
For Local TempObject:Object = EachIn MyList Print TempObject Next
The above code does not work! It shouldn't. It may be obvious that we can't print a Ship, but the String? No neither of them will print straight off (Casting again). You first have to tell Bmax you want to convert the tempObject to a string or a ship and then print them in turn. Replace both of the each-in loops with this loop.
For Local TempObject:Object = EachIn MyList Local TempShip:TShip = TShip(TempObject) Local TempString$ = String(TempObject) If TempShip Print "This Object is a Ship it's Name is: "+TempShip.Name If TempString Print "String Object :"+TempString If Not TempShip And Not TempString Print "Unknown Object in List" Next
If you would have added another object to the loop it would not print. Above I used casting to see the objects true type. See casting for more information.
Strict Global MyList:TList MyList = CreateList() MyList.AddLast("Car") MyList.AddLast("Bus") MyList.AddLast("Airplane") MyList.AddLast("Boat") MyList.AddLast("Train") MyList.AddLast("UFO") Print "--LIST--" For Local Vehicle$ = EachIn MyList Print Vehicle$ Next 'Let's say we want to add a Tank after bus MyList.InsertAfterLink("Tank" , MyList.FindLink("Bus") ) 'This would be the same as'MyList.InsertBeforeLink("Tank" , MyList.FindLink("Airplane") ) Print "--LIST--With a Tank After Bus" For Local Vehicle$ = EachIn MyList Print Vehicle$ Next
InsertBeforeLink takes an Object and puts it before a Link. InsertBeforeLink( Object , TLink ). To get a TLink in our list we search the List for an Object "Bus". In this case it's a string so it's easy. If there are more strings with the same name it will take the first it encounters that match. The FindLink command checks the list for an object. So to use it you have to know the object. Like in our example you could use Ship,Ship2,Ship3 as reference to the object and FindLink would then retrieve that Link which you in turn can use with the other commands. You can also use the Method Contains MyList.Contains(Ship3) to check if that object exists in the list.
To Index | Next Page | page 15