Why I do not like "main()" in the BGE

I see code snippets using the descriptor “main()” quite often in this forum.

To be honest when I see “main()” it means for me -> a beginner was learning from a beginner.
Unfortunately this beginners code distributes even further.

Why I do not like it:

  • The function “main()” is common technique in a different context (“the main function is where a program starts its execution”). Using main() in a different context is distracting and should be avoided.
  • It describes no operation (except the meaning from first point). Nobody can tell what a ‘main’ operation is supposed to do. “main” by its definition is a quality, rather than an operation. If there are other operations - what is the difference to the remaining code?
  • There is no situation when the BGE ever expect the descriptor “main”. It is pure custom code. If it is custom code it is better to add a value by choosing a descriptive (and matching) name. This will show that you know what you are doing. Examples: “move”, “jump”, “putDistanceIntoProperty”
  • There is no convention to Python to create the descriptor “main()”. The descriptor in Python is called main and has a complete different purpose which does not belong to the BGE.
  • One of the purposes of a function is to encapsulate implementation details. A descriptive name tells the reader what the encapsulated code is supposed to do, without forcing him to looking at its implementation. A non-descriptive name prevents the reader from understanding the higher abstraction of the code and makes it hard to read.

There are rare situations, when you might use it.

  • You might use it to demonstrating code. It can be used as a placeholder of yet-undefined implementation which is not part of the code to demonstrate. I prefer to directly name that code so it is easier to be identified as place holder e.g. “doSomething()”, “processYourCode()”. Even a beginner would like to rename it before using which leads to understandable code.

Background
I know main(args) from C and Java to describe the entry point of the compiled application. This is because the developers of C can’t know what your application is supposed to do. So it is a convention of the language or better the API ;). I checked Python. It does not have this convention -> no reason to use it at all.

Hint: If you can’t think of a good name for your functions better resist to use such generic names like “main” or “process”. If you can’t find a descriptive name, it usually means the code is doing too much. To solve this conflict you can extract the different operations into separate functions.

I don’t know what you mean by: “the developers of C can’t know what your application is supposed to do” -> The developers of Python are no more prescient, and the concept of an “execution entry point” is equally relevant as it would be in a compiled language.

So, “main” is not a “generic name”: it describes the entry point. The meaning is largely traditional, and one can make a good argument for why “update” would be better, but “main” does have a pretty clear meaning, to most programmers.

That said: I strongly agree with your larger point, about the importance of descriptive naming.

The C syntax was designed to pick a function as entry point to be called at application start. They decided to use a function with the name “main”. So it is sort of a pseudo-keyword. If I had the choice I would call it: “startGame”, “runGameLoop” or so as I know what is supposed to do. But C was earlier, so how should they know what I want to do.

Python is in that way different that the entry point has no name at all. The application simply starts with the first statement. And that is the reason why there is no main() in the Python language and no need to define it by yourself. So you are free to choose any name you want.

It is the same as with BGE script mode. You do not even need a function (so you do not need to choose a name ;)).

The “tradition” belongs to the according languages in the according context only (C, Java + application entry point). Using it somewhere else displaces the “tradition” into a context it does not belong to. This is another strong argument against main() in the BGE as it is a different context (->no application entry point; -> no according language).
[Edit] If I think about that … yes, this is what disturbs me most an the usage of main(). Used in the BGE it is the incorrect context.

When I see “main”, I think … this is a system and this part is the important (main) part of the system. What is it doing and what other parts exist? None of these questions can be answered without digging through the code.

The question on “update” is “What gets updated?”. Usually I can assume it from context. E.g. score.update() or updateScore(). It is still general, but much more specific then main. At least it tells whats going on -> it is updating.

So what is the difference? See:
score.main() vs. score.update()

[Indeed the context must be sufficient to guess what happens: application.update is pretty weak.]

Script mode
In the context of the script mode in the BGE: If there is just one function, with a non-descriptive name, you can reduce complexity by removing it.
If you have multiple functions, they should have descriptive names so it is easy to tell what they are good for.

Yes, the entry point is implicit, and you’re not restricted to a specific name, but if you wanted to make it explicit, “main” would be a descriptive name, because it was traditionaly used to define the entry point.

Regarding “tradition” - it belongs to the according languages in the according context only (C, Java + application entry point). Using it somewhere else displaces the “tradition” into a context it does not belong to. This is another strong argument against main() in the BGE as it is a different context (->no application entry point; -> no according language).

I think the concept of an “entry point” is more general than just “application entry point”.

Given Player.py, Player.main is the entry point for all the code that needs to run for the Player object, and that seems fairly obvious, doesn’t it?

One could make an argument for Player.update, but I think main makes more sense, in general terms, because there are cases where you don’t necessarily want to update anything about the Player, but you still need to run some code related to the Player object.

As for Script mode: There’s really no need for it, now that we have Module mode, so I think it should be removed.

I still disagree. It is used as application point only as far as I know. There is no additional meaning.

Player.main does not tell anything (except the author wants me to look at the code. But for what?)
Player.update lacks a definition what update means the same way as main lacks a definition what main does.

The most general naming would be Player.live ;).

Why should there be a single entry point to “all the code that needs to run for the Player object”? This sounds like bypassing the SCA event system.

Usually the Python controller should react on events (sensor input). It should not be that difficult to express what happens when an event occurs. E.g. keyboard input -> Player.move

An entry point is a general concept: It can relate to an application, a subsystem, or an object.

The most general naming would be Player.live

Only if all your objects are “alive”. :wink:

Unlike main, it wouldn’t make sense for inanimate objects.

Why should there be a single entry point to “all the code that needs to run for the Player object”?

Because in an OOP context, where you have code to execute for each relevant object (independent of the SCA paradigm, for the most part), that would be a reasonable setup.

If you want to adhere to the SCA paradigm, as much as possible, then it wouldn’t make sense, and I would completely agree with you.

I think you refer to an interface -> each supporting object shares the same interface. This way the using objects can interact with supporting objects without knowing their implementation. (Typically an interface describes more than just one contact point).

Here it is much more important to use meaningful names. Otherwise I would not know what an object is supposed to do. And I would not even know how to implement anything.

I still think main does not describe an operation, it describes a quality.

I think it varies from the situation you are in. In most occasions ‘main’ wouldn’t be a good description, because most of the time functions are part of the rest of the code. But when things are principal, what better name is there to use? To call something ‘main’ is describing it as ‘independent’, ‘head’, ‘predominant, most (important), chief, principal’, ‘broad’, … When a function is in fact used as an entry point to all the code on a particular object, then ‘main’ gives the best description to it, obviously.

It then depends on your programming style and on the program itself. Some put all functionality of the player into one script without using sensors or actuators except for an Always sensor running every tic. Some don’t. But who does also has to name the entry point. For example:

from bge.types import KX_GameObject

class Player(KX_GameObject):
    
    def __init__(self, game_obj):
        pass
    
    def update(self):
        pass
    
def main(cont):
    player = cont.owner
    if not isinstance(player, Player):
        player = Player(player)
    player.update()

You could replace ‘main’ with ‘update’ but I wouldn’t like it because this would imply it’s only an entry point for the function ‘update’ of the class ‘Player’. But it’s doing more than this. It also gets the player, it initializes the class ‘Player’, running all functions, not only ‘update’.

Indeed as you write “main” does not describe an operation, it describes a quality or classification (like long, heavy, rich). This is especially irritating, when there is no other operation to be compared against.

Obviously the best name for an entry point is “entry point”, isn’t it ;)?

You use “main” to encapsulate “update”. The example would be more understandable if both calls are called the same. In that case I think “update” is the better choice as it describes the operation. As a reader I would expect it does some sort of update to the player model.

The module function performs update at an higher abstraction level, while retrieving the player and executing the players update is at a lower abstraction level. A more specific name would be “updatePlayer” as that is what it does.

(I recommend to encapsulate the “retrieve player” implementation too as it belongs to a lower abstraction level. Together with the meaningless name it distracts the reader from what that code is supposed to do. As a reader I do not want to dig through code that grabs a player object. It is enough to state it does that. E.g.


def updatePlayer():
    player = getPlayer()
    player.update()

I can see your points. I will consider them, especially your last.

Entry points are not supposed to describe a specific operation; your irritation here is irrational.

Obviously the best name for an entry point is “entry point”, isn’t it ?

Actually, “main” is more general, while being equally descriptive: There are many who don’t understand what “entry point” means, but who intuitively understand that main is the main/core/central function to be executed for the file in question (typically, on every frame).

I think “update” is the better choice as it describes the operation.

What if I’m running code that is related to Player, but which doesn’t actually update any aspect of Player?

The name “update” wouldn’t make sense in that case, but “main” would.

As a reader I do not want to dig through code that grabs a player object.

Initialization code should run in its own function:


def init(cont):
    Player(cont.owner)

def main(cont):
    cont.owner.main()

I see you have a special “intuitive” meaning of main in your mind. I still do not think it means anything. You can still do main, no problem.

If you run code related to the player which does not update the player, requires a name that describes what it is supposed to do. Unfortunately main, is either used already or just useless as mentioned above, so how would you name it than?

Yes, initialization code can be in a separate code block, but it this depends on the situation, what initalization means.

It seems to me especially important to give descriptive names to functions because of the debugging process.

when I check the console after something went wrong I want to see that there was an error in player_update, not that there was an error in main. As it is it can sometimes be difficult to track back through each level of encapsulation to find where the defective code is.

For example an error in my graph_builder will raise a further error in my a_star function flowing back through the route_finder script and ending up with an error in the movement_manager.

The resulting console report is only useful to me if it contains descriptive functions. If the error repot is main>move>go>check>find>combine for instance it helps me not at all (unless I can memorize all the functions in my game), let alone some other poor sap trying to debug my code. :slight_smile:

But, like stated before, main is just the entry point… So you’re never supposed to get, “error in object.main, line 6043”, you’re supposed to get something like, “error in ‘method’ line 154, from object.main”.

I haven’t really considered the reason behind main (at least prior to reading this thread), but I’ve inferred it as the method that handles the states, updates or processes of an object/program. Said differently, it looks to me that main is where programmers would look to see what an object/program does. If that’s the case, it doesn’t seem “useless” to me.

It’s not just me. :wink:

I still do not think it means anything.

https://www.google.com/search?q=define:main

If you run code related to the player which does not update the player, requires a name that describes what it is supposed to do. Unfortunately main, is either used already or just useless as mentioned above, so how would you name it than?

… ?

I think there was a misunderstanding here: I’m talking about a situation where a programmer wishes to follow the OOP paradigm, independent of the SCA paradigm (as much as possible). So, there are only a few controllers, of which one calls main, which in turn calls whatever code actually needs to run for the object (which could be one, or many different operations, based on various conditions).

Basically, the logic brick system is just used to call the main python function, which takes care of everything else.

In that context, it’s sensible to have an entry point, and it’s equally sensible to call it “main”, isn’t it?

I suppose in a case where you have a number of functions in a script that may or may not be called in a given frame (or are called several times so splitting everything into functions means fewer redundant lines), using main() might make some sense, but often I see something like


g = bge.logic
cont = g.getCurrentController()
own = cont.owner

def main():
     own.worldPosition.x += 0.1

main()

In situations like that, where the script does a small number of very simple things, using main just adds unnecessary lines and makes it slightly more annoying to read without lending any advantages.

Either that, or “Beyond this point, there may be Narnia”, and hope that you find yourself on an amusing program excepts website :wink:

I think you refer to an interface that one part refers to an currently not known implementation.

Example: a state machine. Typically the state machine calls a specific method of a state to performs its actions. Therefore you need to define an entry point to do that.

With your argumentation you would call it “main” assuming a user can guess what sort of implementation is expected. Unfortunately he needs to check the documentation. If there is none, he is lost.

A better name would be state.executeActions, runActions, performActions or whatever. If you want to add entry and exit actions the “main” approach would be even more insufficient (e.g. executeEntryActions, executeExitActions, executeStateActions). None of the entry points are qualified to be called “the main operation”.

So I still think “main” means nothing but indicates there is more and if there are more “main” does not tell the difference to the other one.

When the door is labeled “Narnia.main”, there’s no doubt about it. :wink:

It’s not labeled “Narnia.update”, because it was developed by thoughtful wizards, who understood that the main operation of this “Narnia” system would, on occasion, affect other worlds, without necessarily affecting the state of Narnia itself.

Clever as foxes they be. :smiley:

There’s no need to guess, because “main” has a very clear meaning in the given context, as I explained.

So, if I look at the logic brick panel, and I see only an always sensor, set to true level, linking to a python controller that calls “Player.main”, I know (along with most other programmers) that this function serves as an entry point to all the code that needs to run, on every tick, for the Player object.

A better name would be state.executeActions, runActions, performActions or whatever.

What kind of “Actions”? “runActions” could refer to “actions performed when the player is running (as opposed to walking)”, but even then, what kind of actions would those be?

See -> In the end, you can’t avoid the fact that you just have this “primary/core/main” piece of code that needs to run repeatedly for the object in question.

You need something generic to describe that, which is what “main” was traditionally used for, and why it makes sense in the context I outlined.

If you want to add entry and exit actions the “main” approach would be even more insufficient (e.g. executeEntryActions, executeExitActions, executeStateActions). None of the entry points are qualified to be called “the main operation”.

I don’t quite understand your point here.


def main(self):
    self.entry()
    self.state()
    self.exit()

As you can see, “main” serves as “the main operation”.

So I still think “main” means nothing but indicates there is more and if there are more “main” does not tell the difference to the other one.

It has a clear definition: https://www.google.com/search?q=define:main

Entry points (for which “main” is traditionally used) are not supposed to describe specific operations, so that’s not a valid argument against “main” as a name for an entry point.

The main conclusion is that ‘main’ can serve as a name to descibe the main of a script.