Modular object programming

I am making a platform engine and am beginning to add classes for enemies,coins,powerups,springs,hazards etc. My first thought would be to make one class for each object but that can quickly get complicated. I could have one object class with if tests or something similar or I could use inheritance. What is the best way to keep code short and modular.

Thanks all.

@Coder for my platform game I have a separate class for every object without inheritance, it’s too easy to get classes to communicate efficiently without inheritance it just stops the need for it, although I think it does have it’s own special behaviours. But as it goes I have a box class and a ball class (both are resizable) and a dynamic class that incorporates a model list with vertices and material with gives it its properties etc. I guess its quite obvious.

Ok thanks i guess I could group similar behaviours together

@Coder I would go with a seperate class. You start adding “if” statements in them and it’ll be even more complicated.

+1 @Luatee, generally its a trade-off of inheritance versus aggregation, for Codea/Lua I’ve generally found that aggregation is a better approach rather than inheritance…

@brookesi could you developp your arguments for saying this?
thanks!

Hi @Jmv38,

Ok, I’m going to crib from a StackOverflow post as I haven’t had enough coffee…hope this makes sense

Inheritance works when you can correctly use all of the the interface of the base class, the thing you are inheriting from. If at any point you find you are only using a small part of the interface to avoid code re-use, then that should probably be extracted and used in the two classes as an aggregate object. If you find you are ‘bending’ the base class interface implementation to support inheritance then, again, it indicates aggregation is better…

As Lua does not support true OO in terms of protected/private access, it just supports the colon operator to pass the calling object as the first argument… My experience in strongly typed languages such as C++ and Java is that as you get to a certain level of complexity, inheritance makes it much harder to understand the execution path through the code, especially if the inheritance levels become deep, generally more than two or three levels…

This is worth a read as it explains it better than me: http://stackoverflow.com/questions/269496/inheritance-vs-aggregation

One good point in the above link is that as your code evolves your OO (inheritance) model is almost guaranteed to be wrong unless you have done a comprehensive design up front to cover all eventualities, in itself an oxymoron…

The famous Design Patterns book (which everyone should look at :wink: http://www.amazon.com/dp/0201633612/?tag=stackoverfl08-20) always favours composition over inheritance…

Also, one of the main reasons for inheritance is to take advantage of polymorphism, e.g. where you have:

class Vehicle
     function numWheels()  return ? this is 'abstract' ? end
end
class Car extends Vehicle
     function numWheels() returns 4 end
end
class Bike extends Vehicle
     function numWheels() return 2 end 
end

Which allows you to pass around objects of type Vehicle whose implementation is subclass specific…

Lua does not allow this without ugly hackery, and does not have the ‘protection’ to stop people from creating base class objects such as thing = Vehicle(), which is an abstraction which you couldn’t normally create…

Google for inheritance vs aggregation, it’s a much debated subject, but for Codea/Lua I find aggregation is cleaner…

Brookesi

Thanks, yes i think that is the way to go

@Brookesi thank you very much for taking the time to share your wisdom.
Btw, i think lua enables some kind of private variables. If you make in a tab:

local hidden = 5
myClass  = class()
function myClass:change(x)
    return x"hidden
end

you can use hidden but cannot change or access it directly.

@Brookesi one more question. Implementing inheritance is defined via class() in lua.
But how would you recommend to implement aggregation?

Hi @Jvm38,

Yes, you are absolutely right regarding locals, and you can create ‘stronger’ interfaces by using them, and then have ‘setters’ and getters’ in the class…

With respect to an example (not great, but hopefully works):

Person = class()
function Person:init(name) self.name = name end

Book = class()
function Book:init(author) self.author = author end

The point is whether the two classes have an ‘is a’ or ‘has a’ relationship…

If you had made author a member of Book, then when you came to have other objects that had ‘people’ e.g. a Film, Podcast or whatever, then you re-use Person…and your Author can exist in multiple Books, if that specific Person instance changes, then ALL Books pick up the change…

Also, if your Person class needs to be extended then you just extend Person, and all classes using it automatically pick up the new fields/functionality…

(Of course, books have multiple authors so you would actually have a table and an :addAuthor() function, and maybe later on you’d add :addReviewer(Person), :addProofreader(Person))

Note that you will also see the term Composition, which is similar to Aggregation but is more of an ‘is part of’ relationship, this implies that the ‘owning’ class manages the lifecycle of an object…

E.g. from the above example, a Person may be an author of multiple books, if a book say, goes out of print, the Person still exists, a better example is a Person with an Address, if a person moves, the Address (in the real world) still exists…

A Composition is more like:

Engine = class()

Car = class()
function Car:init()
    self.engine = Engine()
end

The Engine ‘is part of’ a Car, if the car is scrapped, then that affects the Engine, not a great example, you could remove an Engine, but hopefully you get the idea…

So in a nutshell, work out the relationship:

IS A: consider inheritance, but ONLY if the interface is ‘clean’, and very few are… Consider a Vehicle base class, by the time you have worked out you want to have subclasses of Car, Bike, Boat and Plane, your base class has very little functionality, Boats don’t have wheels, or engines perhaps, only Planes have wings…your Vehicle base class ends up with very little reusable functionality after trying to subclass all the flavours of Vehicle, maybe it works, Vehicles have Manufacturers, and RegistrationNumbers, but even so, it is still better to have those as separate classes (IMHO) because the more you try and create subclasses of WheeledVehicle, WaterVehicle etc., the more mangled your inheritance tree gets, e.g. when you get to AmphibiousVehicle!!! ;))

HAS A, or IS PART OF: Create separate classes and ‘slot’ them into other classes as self. = Thing(…) either by passing them into :init() or creating them inside :init

Brookesi

@Brookesi thanks a lot for these detailed explanations. They will be very usefull to me. I can already see there one of the root cause of my difficulty to manage big, evolutive, programs.

Hi @Jvm38, my pleasure :wink:

I’m 10 months into my first game (part-time!), about 700 hours of programming overall, so I’ve reached a major level of complexity with multiple views, event passing, writing my own UI for buttons, sprite management etc., etc. We are nearly dev complete with testing and balancing commencing July and August, hopefully releasing in September :wink:

I’m thinking of writing up the development process for complex Codea programming as it has been a fun ride!

@Brookesi wow! please do write this, i’ll be eager to read it.