10.03.2019 - Round 1 results of our "A Love Letter For FreeBASIC" game dev competition have been published. Please be sure to check the results thread: http://games.freebasic.net/forum/index.php?topic=629.0. Don't forget that the competition is continuing with a round 2, lasting till 29th of April, 300 USD first prize. Stay tuned!

Author Topic: Why OOP?  (Read 13007 times)

notthecheatr

  • Global Moderator
  • Forum Sage
  • *****
  • Posts: 351
  • Who's the guy from 21 Jump Street?
    • AOL Instant Messenger - notthecheatr
    • Yahoo Instant Messenger - TheMysteriousStrangerFromMars
    • View Profile
    • notthecheatr Home
    • Email
Why OOP?
« on: January 23, 2008, 02:19:07 PM »
OOP might be a really nice convention for programmers to adopt when writing their big projects that they're being paid to write, but why should a game programmer bother with it?  This is essentially the question asked by someone recently rather off-topically in a discussion.  Rather than start a heated debate on the pros and cons of OOP (though there were plenty of replies and it started getting there...) I'm going to try to answer that question here.

We start with the origin of procedural programming.  In the beginning, you didn't have procedures.  You basically had spaghetti code - along with capital letters, line numbers, and all that ugly stuff:

Code: [Select]
100 PRINT "I AM A DOOF."
200 GOTO 100

Although it doesn't matter much in a small program like that, it gets to be extremely difficult in large programs.  Hard to read, etc.  Even hard to write.

So programmers somewhere, one day, decided to do this:

Code: [Select]
Do
  Print "I am a Doof."
Loop

and furthermore, they even decided to do this:

Code: [Select]
Sub printDoof
  Print "I am a Doof."
End Sub

Do
  printDoof
Loop

How very structured of them!  Now for some, it may have been easiest to stick with the GOTO's.  Amazing though it may seem, there are still some programmers who use it.  I don't know how they can write anything useful (and really try to debug, or make any modifications to it) that way, but some do.  But for the most part, programmers today have adopted much more structured syntax.  Now it's no more powerful - you can still write the exact same code with GOTOs as you can procedurally - but it's much easier for we humans to understand, debug, modify, maintenance, etc.  So we use it.

With structured programming, someone eventually figured out a rather neat idea.  You see, your Subs and Functions might tend to get kind of long:

Code: [Select]
Sub moveSprite (sprite As FB.Image Ptr, x As Integer, y As Integer, vx As Integer, vy As Integer, suchandsuch As uInteger, thisthatandtheother As Byte)
  '...
End Sub

See what I mean?  You will be passing twenty different parameters to it, and eventually you realize it would be a lot easier if you could group these parameters together.  So here comes the concept of the UDT.  Put a bunch of variables in a single structure, like a package, then send the whole thing to the Sub, which means you only have to pass one (or maybe a couple) parameters, instead of twenty.

Code: [Select]
Type myUDT
  As Integer a, b, c, d, e, f, g, h, i, j
End Type

'Which do you like better?
Sub mySub1 (param1 As myUDT)
End Sub

Sub mySub2 (a As Integer, b As Integer, c As Integer, d As Integer ...)
End Sub

But there's another factor we need to look at.  That is scope.  In the beginning, everything was global.  That means
you would create a variable for your program

Code: [Select]
110 DIM A AS STRING = "I AM A DOOF."
120 PRINT A
130 GOTO 120

and the variable would be accessible everywhere.  Of course, that was because you didn't even have procedures yet, so it was practically pointless to hide anything from any other part of the program.  But once you had procedural programming, it became useful to make variables inside procedures that weren't necessarily accessible (in fact, didn't necessarily even exist) anywhere else.  Then you could have a variable called X in your main program and a variable called X in your procedure and they would be entirely different variables, and neither could access the other.  If the main program needed to give some information to the procedure that the procedure didn't have, it could simply pass a parameter to the procedure.  But this didn't always work, so we still had some global variables lying around:

Code: [Select]
Dim Shared As Integer mynumber

Sub mySub
  Print mynumber
End Sub

mynumber = 3
mySub
mynumber = 5
mySub

Now the same variable name is the same variable whether inside the procedure or out.  And many people thought this was great, because then you don't have to have a lot of parameters passed to and from your procedures (these people didn't know about UDTs yet, of course).

But there's just a little problem.  What if you have a global variable and you have twenty different procedures that access it, maybe even modify it, and who knows what happens then?  Maybe a bank program storing the balance of an account as a global variable.  A bug is bound to happen sometime somewhere, with all that code, and you suddenly realize that the balance is off - way off.  So which one of those twenty different procedures messed it up? And remember, this is a bank program, so it's probably made up of hundreds of lines of code, each of which might potentially access the account balance.  That means hours of debugging for you.  And in case you think I'm only talking about business programs - what about games?  What if you store the sprite position x and y in global variables, you have twenty different procedures moving the sprite around and drawing it on the screen, and you suddenly notice the sprite is going all over the place on the screen and it's not where it's supposed to be?  Then what?  So which of those procedures did it?

Scope solves this.  Only certain procedures can modify certain things, so you know which procedures to check and see if they modified it - and most of them don't, because you only let certain ones do it.  So what if those procedures need to modify it?  Then you pass things ByRef, and at least now you know which one did it.  But that's not always safe, so we could run into problems there.  Enter the UDT.  It solves the problem of too many parameters, and since you pass it as a parameter to the procedures, you don't have the problems of global variables.  Everything is in its proper scope, so you have one less thing to worry about.  Unfortunately, if the procedures want to modify the variables inside the UDT, you have to pass it ByRef.  And then you can have problems that way just like with global variables, because if you pass it ByRef to everything, you'll still have twenty procedures potentially modifying variables and messing things up.  Now what?  We need more scope rules!

This is what encapsulation is all about.  You put the variables inside a UDT, but make some of them Private.  What's that mean?  That means nobody else can access those variables!  They're hidden inside the UDT, so even if I pass the UDT to a procedure, the procedure can't access those variables.  In fact, even the procedure (or main program) that creates the UDT can't access the variables:

Code: [Select]
Type myUDT
  Public:
    As Integer a
  Private:
    As Integer b
End Type

Dim something As myUDT

'This is OK
something.a = 3
Print something.a

'This is NOT OK
something.b = 5
Print something.b

But of course that begs the question who CAN access the variables?  Because if nobody can access the variable at all, then what's the point?  In a sprite, you might hide the x and y variables so nobody can just move the sprite around whenever they want.  But if nobody can access the (x, y) variables, then how does ANYONE move the sprite?  And how would we know where to draw it?

This is why we add things called methods to the UDT.  It's the beginning of OOP.  It may seem a little strange, but it really solves a lot of problems.  Now only ONE procedure can modify the sprite's position, and if there's any bugs you know who did it!

Code: [Select]
Type mySprite
  Public:
    Declare Sub move (newx As Integer, newy As Integer)
    Declare Sub draw ()
  Private:
    As Integer x, y
End Type

Sub mySprite.move (newx As Integer, newy As Integer
  x = newx
  y = newy
End Sub

Sub mySprite.draw ()
  PSet (x, y), &hffffff
End Sub

Now you could just as easily do it like:

Code: [Select]
Type mySprite
    As Integer x, y
End Type

Sub moveSprite (tsprite As mySprite, newx As Integer, newy As Integer
  tsprite.x = newx
  tsprite.y = newy
End Sub

Sub drawSprite (tsprite As mySprite)
  PSet (tsprite.x, tsprite.y), &hffffff
End Sub

But then you lose the encapsulation and you still have scope issues because anyone else can access x and y.  This example also illustrates something else we need to examine: style.

You might not think it matters, but it does.  For example, although indentation doesn't really have any effect on what a program does, it's still a lot easier to read

Code: [Select]
If something = 1 Then
  Do
    Print "Hi"
  Loop While something = 1
End If

than

Code: [Select]
If something = 1 Then
Do
Print "Hi"
Loop While something = 1
End If

And there are other areas this applies.  Now if you have a UDT and a bunch of procedures that deal with that UDT specifically, it eventually becomes logical that those subs should be part of that UDT, rather than separate entities.  It also simulates real life;  for example, in the corporate structure, your executive gives out tasks for his employees to do.  The boss doesn't balance finances using the employee, he tells his employee to do it!  So likewise it seems much more logical to tell the sprite to draw itself, rather than to tell a procedure to draw a sprite using the UDT that contains it.  Or a map object, for example:

Code: [Select]
Type mapType
  As Integer x, y
  As Any Ptr tiles
End Type

Declare Sub loadMap (filename As String, map As mapType)
Declare Sub drawMap (map As mapType)
Declare Sub moveMap (map As mapType, x As Integer, y As Integer)

Notice anything about all these subs?  They all have a parameter called "map As mapType"!  But if you use OOP, you don't have that.  In fact, you can just call the subs "map.load, map.move, and map.draw" instead of "loadMap, drawMap, and moveMap".  Nor do you pass a map parameter to them;  they're part of a map object, so they have a hidden parameter passed to them.

Hopefully you're getting an idea of why OOP makes sense.  It's really just another abstraction which takes some ideas to the next level.  UDTs don't exist in real life;  neither do procedures for that matter.  At the low level, the variables are separate, the procedures in the UDTs are not "part of" anything at all, and all procedures are really just Goto statements (actually, it's a little better than that but I won't go into the details).  But OOP saves you from scoping problems, allows you to work much more easily, and makes your code look nicer and more logical too!

But OOP goes beyond making code nicer and more logical.  It makes a lot of things simpler, and generally lets you do some very interesting things you otherwise couldn't do.  For example, strings.  Normally the + is used to add two numbers, but what if you want to use it to concatenate two strings?  That's what operator overloading is for!  If you make a string object, you can use the + operator for the object and it does something totally different!  You can do this with pretty much all the other standard operators too.

And then there's RAII.

cha0s wrote a tutorial about RAII too, but some people might not understand it so well.  What it basically means is, when you create an object the object keeps track of all the resources it needs.  Take for example a buffer in memory.  If you create a buffer (say, to store your map data) then you need to use a pointer, and you need to Allocate/ReAllocate/DeAllocate.  Now what if you forget to DeAllocate?  You may eventually get memory leaks and problems!  But if you put it inside an object, the object will automatically allocate the memory it needs when it needs it, and as soon as the object is destroyed (which will be at the end of the program or at the end of the procedure it's created in, depending on the scope) it will automatically deallocate the memory, thus ensuring you won't get any leaks (or wasted memory) by forgetting to deallocate a buffer when you're done with it.

This is done with Constructors and Destructors, which are two special kinds of procedures that are called automatically as soon as the object is created or destroyed.  The other nice thing about them is that they let you set the object up, make sure the object is valid before you call any other methods.  For example, you might want to draw your map, but what if you forgot to load it?  Then the pointer to the buffer containing the map data is invalid and when you try to draw the map your program will likely crash.  But if you have a Constructor, which gets called automatically no matter what, then it can set a special flag inside the object explaining that the map has not been loaded so it shouldn't be used.  You can also allocate the pointer, so when the map loading routine needs to reallocate there's something to reallocate (and of course the destructor will deallocate it):

Code: [Select]
Type mapType
  Public:
    Declare Constructor ()
    Declare Destructor ()

    Declare Sub load (filename As String)
    Declare Sub draw ()
    Declare Sub move (newx As Integer, newy As Integer)
  Private:
    As uByte Ptr _map_data
    As uInteger _map_width, map_height
    As Integer _x, _y
End Type

Now if we were to call draw() without a constructor, it would check the buffer at _map_data for tiles to draw.  But the map hasn't been loaded yet, so the buffer is empty!  This could very well cause a crash!  But if the constructor is used, the constructor sets everything up ahead of time so no errors can occur.

Now of course in practice, you would be very careful not to call draw() until you call load().  But if you forget, or make a mistake, setting things up this way can save you a lot of trouble.

Another thing OOP lets you do is Properties.  Now as I said earlier we want to hide all the variables inside the object where nobody else can access them, because otherwise we can have problems.  But always using a sub to access the variables may seem rather uncomforable.  This is why we use properties.  They seem like variables, and they act just like variables - for example, if x is a property of myUDT, then you can do

Code: [Select]
myUDT.x = 3
Print myUDT.x

but in reality, properties are actually a special kind of procedure, meaning when you try to modify a variable you aren't just directly modifying it, you're actually instructing the object to modify it.  This way, for example if you had a property map.x the map could redraw itself automatically when you modify map.x.  This wouldn't happen if you tried to modify the variable directly, but since a property is really a sub in disguise you can do that.  This way, you avoid the scope problems but you don't have to use the rather uncomfortable sub just to modify things.

Of course, how you do things is entirely up to you.  It might be easier at first not to use properties, operators, or even constructors and destructors.  These things are just special extras that come with the OOP paradigm.  You may want to start out just using methods and keeping all variables Private.  It's still much safer and smarter than using UDTs with everything public.  And you'll start to get a feel for OOP, and maybe even learn to enjoy it and prefer it to just plain procedural programming.

OOP is not the be-all and end-all solution to everything.  I don't use OOP everywhere, by any means - but I do use it whenever I can, because it can save me a lot of trouble and make sure I do things right.  And by the way, OOP and procedural programming can be done side-by-side.  As I said, I don't use OOP for everything - for some things, a plain old-fashioned function or sub will work just fine.  But when it's possible, when it's useful, when it makes things easier, safer, and cleaner, I use OOP.
« Last Edit: January 23, 2008, 07:06:43 PM by notthecheatr »
The funniest thing happened yesterday.

dabooda

  • Forum Howler
  • ****
  • Posts: 123
    • View Profile
    • DaBooda Gaming
    • Email
Re: Why OOP?
« Reply #1 on: January 23, 2008, 02:59:41 PM »
Good stuff!! You really encapsulated OOP within a very nice and clean explanation. The only issue I have and I believe it to be beyond the scope of this tutorial, and that is the benefits to function overloading. I understand what it is, but I have yet to see any reason to do this. Again this is probably beyond the scope of this topic. But you are right if it wasn't for OOP my old school library would have been a total nightmare...and large projects just make sense with it.

DaBooda out...
Baa...Baa...Bang! F&#K! I'm Wool!

notthecheatr

  • Global Moderator
  • Forum Sage
  • *****
  • Posts: 351
  • Who's the guy from 21 Jump Street?
    • AOL Instant Messenger - notthecheatr
    • Yahoo Instant Messenger - TheMysteriousStrangerFromMars
    • View Profile
    • notthecheatr Home
    • Email
Re: Why OOP?
« Reply #2 on: January 23, 2008, 03:10:42 PM »
Thanks!  The goal is to help people understand better why OOP is useful and good.  I know when I first saw OOP I thought "it's cool but it needlessly complicates things."  It wasn't until I started using UDTs that I realized how nice OOP really is.  (And as it showed in the example, I began to notice that all my procedures had an argument "someUDT as UDT" and eventually decided how much easier it would be just to use OOP.)

About function overloading, it would probably help if I could think of a solid example.  I use it myself occasionally, but far less often than any of the other things.
The funniest thing happened yesterday.

KristopherWindsor

  • Forum Sage
  • *****
  • Posts: 363
  • The Thirsty Smiley
    • View Profile
    • Reddit/r/pics
    • Email
Re: Why OOP?
« Reply #3 on: January 23, 2008, 03:30:31 PM »
I used OOP in a rather awesome way for iGUI, since that was a library, but for mid-sized or small games it is not good. Ie. I have a Sub called missile_move() which moves all the missiles and handles collision, but Sub was a UDT member I would have to replace that one call with:
Code: [Select]
for a as integer = 1 to missile_total
  with missiles(a)
    .move()
  end with
next a

notthecheatr

  • Global Moderator
  • Forum Sage
  • *****
  • Posts: 351
  • Who's the guy from 21 Jump Street?
    • AOL Instant Messenger - notthecheatr
    • Yahoo Instant Messenger - TheMysteriousStrangerFromMars
    • View Profile
    • notthecheatr Home
    • Email
Re: Why OOP?
« Reply #4 on: January 23, 2008, 03:55:34 PM »
Well as I said in my concluding paragraph, OOP is not the be-all and end-all solution for everything and I can't think of any program where the entire program would or should rely solely on OOP to do everything.  OOP is just a nice tool which is very useful for organizing things, and this is intended to show some people (who think OOP is too bothersome to be used at all) that there are some valid ways of using OOP that might actually be better than procedural programming.


For your particular example (I don't know how your code is setup, but here's my take on the situation), you could have a missleManager object which keeps track of all the missiles on the screen, and it would have a missleMove() sub which could contain the code you posted.  However, I wouldn't implement the individual missiles as objects, I'd just use regular UDTs with public variables:

Code: [Select]
Type vector2d
  As Single x, y
End Type

Type missile
  As vector2d position, velocity, acceleration
End Type

Type missileManager
  Public:
    Declare Constructor ()
    Declare Destructor ()

    Declare Sub update()
    Declare Sub draw()

    Declare Sub addMissile ()

    Declare Sub pause()
    Declare Sub unpause()

    'etc.


  Private:
    As missile Ptr _missiles
    As uInteger _num_missiles

    'etc.

End Type

You get the idea.  In this case, update() would be the equivalent of your moveMissile() and you'd essentially only have to call update() once and all the missiles would be moved (of course in this case you'd also want other control subs or properties which I didn't bother to list, to allow you to control which missiles move which way, etc.)

This is also how I would implement particles;  the individual particles don't use OOP (too slow, since you might have thousands of particles on the screen and constantly having to call a drawing routine for each is no fun) but there's a parent called particleManager or the like that does all the work.
The funniest thing happened yesterday.

Lachie Dazdarian

  • Double dipper
  • Administrator
  • Forum Sage
  • *****
  • Posts: 1308
    • Yahoo Instant Messenger - lachie13
    • View Profile
    • The Maker Of Stuff
    • Email
Re: Why OOP?
« Reply #5 on: January 23, 2008, 04:58:33 PM »
This is very interesting. And quite well explained. Thanks. I'll definitely think about using OOP in a new project that will be written from scratch. Of course, side-by-side with procedural parts of code.
"Things like Basic and Free Basic provide much-needed therapy and a return to sanity and a correct appreciation of people. The arrogant folk really hate a word like 'Basic' - fine, and good riddance." ~ pragmatist

notthecheatr

  • Global Moderator
  • Forum Sage
  • *****
  • Posts: 351
  • Who's the guy from 21 Jump Street?
    • AOL Instant Messenger - notthecheatr
    • Yahoo Instant Messenger - TheMysteriousStrangerFromMars
    • View Profile
    • notthecheatr Home
    • Email
Re: Why OOP?
« Reply #6 on: January 23, 2008, 05:06:21 PM »
This is very interesting. And quite well explained. Thanks. I'll definitely think about using OOP in a new project that will be written from scratch. Of course, side-by-side with procedural parts of code.

Of course  :D OOP isn't intended to be the death of procedural programming by any means, just to bring new life to it with more variety and nicer code.
The funniest thing happened yesterday.

Pritchard

  • Global Moderator
  • Forum Howler
  • *****
  • Posts: 160
    • View Profile
    • Email
Re: Why OOP?
« Reply #7 on: January 23, 2008, 06:41:09 PM »
Love this one.  Beginners should really read it.  OO has a lot of uses.  Unfortunately, a lot are beyond the scope of what FB can currently do...  And yeah, OO was made to solve problems.  When programming ANYTHING, it's not a case of just doing something OO for the sake of OO.  The question for programmers becomes, "What is OO solving for me?  What does using Inheritance over Composition Provide?  Does it make sense?  What problem would I run into if I did otherwise?"


Gotta say that method overloading is important.  Take a look at this:

Code: [Select]
MoveCar_WithStick()
MoveCar_WithFoot()

Now let's say that the behavior of both was that the car still moved - All that's changing is what you're using to move it.  It doesn't make much sense to have two functions that do the same thing.  In general, you want to keep your API working how people expect it to work, and how the object is interacted with.  Additional functions with no additional functionality doesn't make sense:

Code: [Select]
MoveCar( Stick that )
MoveCar( Foot that )

Looks better, and makes more sense.  At the low level, this makes no sense, but when you're thinking of your classes as real objects, which exist and interact with things - What's the difference between a stick and a foot in this situation?  They might look like this internally:

Code: [Select]
sub MoveCar( Stick that )
  '' make that into moveable object and move the car!
  moveWith( that.matter )
end sub

sub MoveCar( Foot that )
  '' make that into moveable object and move the car!
  moveWith( that.body )
end sub
« Last Edit: January 23, 2008, 06:42:39 PM by Pritchard »

notthecheatr

  • Global Moderator
  • Forum Sage
  • *****
  • Posts: 351
  • Who's the guy from 21 Jump Street?
    • AOL Instant Messenger - notthecheatr
    • Yahoo Instant Messenger - TheMysteriousStrangerFromMars
    • View Profile
    • notthecheatr Home
    • Email
Re: Why OOP?
« Reply #8 on: January 23, 2008, 07:12:22 PM »
Love this one.  Beginners should really read it.  OO has a lot of uses.  Unfortunately, a lot are beyond the scope of what FB can currently do...  And yeah, OO was made to solve problems.  When programming ANYTHING, it's not a case of just doing something OO for the sake of OO.  The question for programmers becomes, "What is OO solving for me?  What does using Inheritance over Composition Provide?  Does it make sense?  What problem would I run into if I did otherwise?"

Agreed.  And it's not intended to replace procedural programming - only to augment it, make things easier on the programmer and neater/cleaner.

And thanks for the method overloading example - although it's kind of abstract (nobody creates car, stick, and foot objects in their program - unless it's a really unique game) - it probably will help clear things up for some people.
The funniest thing happened yesterday.

mysoft

  • Recruit
  • **
  • Posts: 48
    • MSN Messenger - mysoft@bol.com.br
    • View Profile
    • MyTDT Software
    • Email
Re: Why OOP?
« Reply #9 on: January 23, 2008, 07:57:57 PM »
good text, as for everything you need to be careful to choice wheter use it and wheter not... cuz in OOP i can say that about 10% of the cpu power is "wasted" in calling properities,subs,functions and things like that... (ofcourse procedural with a lot of subs and functions have this waste too)...

you know the easy path isnt always the best way =]

Programming is like love... you will never acomplish anything by treating your language as if it was a tool, or a slave of yours...

notthecheatr

  • Global Moderator
  • Forum Sage
  • *****
  • Posts: 351
  • Who's the guy from 21 Jump Street?
    • AOL Instant Messenger - notthecheatr
    • Yahoo Instant Messenger - TheMysteriousStrangerFromMars
    • View Profile
    • notthecheatr Home
    • Email
Re: Why OOP?
« Reply #10 on: January 23, 2008, 08:06:43 PM »
That's entirely true, you can have big slow-downs if you try to use procedures all the time, including methods in objects (including properties, which act like variables but are really procedures - in fact, if there's a variable you access often and don't much care about scope, you shouldn't bother to use properties as it'll just be a huge slowdown).

I alluded to this in the example I posted for K.W. too - don't have a missile object, the missiles should be just plain UDTs.  Do, however, hide them inside a missileManager so you still have the benefits of encapsulation while not having an overall slow-down per missile (instead the slow-down will only be per missile manager, which if you only have one missile manager but lots of missiles will be a big difference).
The funniest thing happened yesterday.

dabooda

  • Forum Howler
  • ****
  • Posts: 123
    • View Profile
    • DaBooda Gaming
    • Email
Re: Why OOP?
« Reply #11 on: January 23, 2008, 08:14:38 PM »
Thank you pritchard for answering that for me. I can see the instances that I will be using overloading to be quite rare, but can optimize some things. As for slow down it isn't that bad unless you make countless udt's for a singular object. Basically make your udt encapsulate the majority of your work and your code really optimized it won't slow down to a point that is even noticeable to a human at least. Like notthecheater stated, don't make 100's of udts for each missile but one that handles all missiles. If I am not wrong accessing properties in an udt is similiar to accessing arrays, all it is addition to a single address like pointers, right?

DaBooda out...
Baa...Baa...Bang! F&#K! I'm Wool!

notthecheatr

  • Global Moderator
  • Forum Sage
  • *****
  • Posts: 351
  • Who's the guy from 21 Jump Street?
    • AOL Instant Messenger - notthecheatr
    • Yahoo Instant Messenger - TheMysteriousStrangerFromMars
    • View Profile
    • notthecheatr Home
    • Email
Re: Why OOP?
« Reply #12 on: January 23, 2008, 08:43:21 PM »
Actually, a property is really just a procedure that can be treated like a variable.  So, for example, your sprite may have four properties:

Code: [Select]
Type sprite
  Public:
    Declare Property x As Integer
    Declare Property x (newx As Integer)
    Declare Property y As Integer
    Declare Property y (newy As Integer)
  Private:
    As Integer _x, _y
End Type

Property sprite.x As Integer
  Return _x
End Property

Property sprite.x (newx As Integer)
  _x = newx
End Property

Property sprite.y As Integer
  Return _y
End Property

Property sprite.y (newy As Integer)
  _y = newy
End Property

This is an oversimplified example, but you get the idea.  The nice thing about this is that it maintains encapsulation, not allowing just anyone to directly access the variables.  Also, for example if you accessed a property that would cause changes it might redraw itself automatically.  Probably not for sprites, but for your map you would likely be able to redraw it just by modifying its x or y property.  The main problem is that you wouldn't be able to modify both simultaneously, so you'd probably end up having a Sub anyways if you wanted to modify both.  But basically, the point of using properties is to maintain encapsulation but not have to use the unwieldy Sub interface just to modify a variable.

But like I said, in the case when you're using a whole lot of an object, you'd best just use it as a regular UDT with all the variables public, then create a "parent" object that actually does the actual work.  Then, once again, you maintain encapsulation (a phrase I seem to be using an awful lot all of a sudden  ;D ) and all the niceties of OOP but you don't slow yourself down to a crawl.
The funniest thing happened yesterday.

notthecheatr

  • Global Moderator
  • Forum Sage
  • *****
  • Posts: 351
  • Who's the guy from 21 Jump Street?
    • AOL Instant Messenger - notthecheatr
    • Yahoo Instant Messenger - TheMysteriousStrangerFromMars
    • View Profile
    • notthecheatr Home
    • Email
Re: Why OOP?
« Reply #13 on: January 23, 2008, 09:04:17 PM »
Oh, sorry - this stuff about speed might not be clear to some.  Explanation:

Procedure calls can slow you down majorly.  If you aim for speed, you won't do much if any procedure calls in a loop.  That means that it would make my code much cleaner if I used functions to do things in my ScaleHalf routine, for example - but it would mean making procedure calls in a loop, which would slow things down to a crawl.

Procedure calls use the stack, even if you don't pass any arguments, because they need to pass one implicit argument:  where to return to after the procedure returns (of course functions also return values, so for functions there are at least two automatic stack usages no matter what).  I can't give an exact cycle count on any of this stuff, suffice to say all the work with the stack (especially considering that it will be the same value every time, hence time is wasted passing information that remains constant) slows you down.

Methods in objects are just procedures, although they may look different.  This includes operator overloading and properties, as well as constructors and destructors and regular subs and functions.  Thus, for speed reasons, you want to keep method calls to a minimum inside loops.  Thus, if you have 1000 particles flying around on the screen, it's not wise for each particle to be an object with hidden data that is accessed through properties, subs, functions, or operator overloading.  You'll get very low fps!  Thus, the solution is to create a particleManager that is encapsulated.  It's the particleManager's job to update, draw, and take care of every single particle.  Particles aren't objects then, just regular UDTs with public variables.
The funniest thing happened yesterday.

Pritchard

  • Global Moderator
  • Forum Howler
  • *****
  • Posts: 160
    • View Profile
    • Email
Re: Why OOP?
« Reply #14 on: January 23, 2008, 09:36:13 PM »
*used method calls for his particles - getPosition(), getX(), getY(), getBuffer(), etc...*