-
Notifications
You must be signed in to change notification settings - Fork 14
Coding style, standards and conventions
This document will be a summary of some common guidelines that should be followed to understand ViX code and to patch it (and hopefully, extend it) in a coherent manner. If you are a new code reader, you are extremely encouraged to read this first.
(To be written).
If you use emacs, you can add this function to your ~/.emacs file to use ViX indentation standards. Just do M-x vix-style before coding:
(defun vix-style ()
(define-key
c-mode-base-map (kbd "RET")
'newline-and-indent)
(c-set-style "linux")
(setq c-basic-offset 2)
(setq-default indent-tabs-mode nil)
)Even though ViX is written in C, it is based in OOP. There are objects, constructors, destructors, inheritance and polymorphism. OOP in ViX is implemented as follows:
Classes are described by means of structures:
struct MYCLASS
{
/* Members */
};The structure describing the class has public and private members (but not pointers to methods or anything). This class name is just an example, please don't use all-caps names in the code, that should be reserved to preprocessor macros.
Constructors are implemented as functions suffixed by _new:
struct MYCLASS *MYCLASS_new (/* Constructor arguments */);The constructor must return a pointer to the instance or NULL if there was an error.
Destructors are implemented as functions suffixed by _destroy:
void MYCLASS_destroy (struct MYCLASS *instance);The destructor must release all resources associated to it and cannot fail. Any aggregated objects must also be destroyed. This is the only method allowed to free or realloc the instance pointer.
Pretty much like constructors and destructors, methods are prefixed with class name and take the instance as their first argument:
int MYCLASS_do_something (struct MYCLASS *instance, <method args>);Like regular methods, but the instance must be a constant argument.
int MYCLASS_read_something (const struct MYCLASS *instance, <method args>);If the object is meant to be used from different threads, they must hold a mutex and implement lock and unlock methods:
void MYCLASS_lock (struct MYCLASS *instance);
void MYCLASS_unlock (struct MYCLASS *instance);Also, thread-unsafe method names must begin with two underscores. Thread-safe versions must be consistent with the thread-unsafe implementations and should be implemented as a simple function that locks the instance, passes the argument to the unsafe implementation, and unlocks it back:
int __MYCLASS_do_something (struct MYCLASS *instance, params);
int MYCLASS_do_something (struct MYCLASS *instance, params)
{
int result;
MYCLASS_lock (instance);
result = __MYCLASS_do_something (instance, params);
MYCLASS_unlock (instance);
return result;
}It's up to the programmer to choose what blocking mechanism is going to be used by the class. However, let's try to be coherent whenever is possible (I mostly use SDL mutexes).
Classes that can be extended must have a way to set and retrieve an opaque pointer to be filled with a pointer to the structure of the specialized part. The methods to get and set this part are:
void *MYCLASS_get_opaque (const struct MYCLASS *parent);
void MYCLASS_set_opaque (struct MYCLASS *parent, void *opaque);Specialized methods should have the name of the specialized class but must accept the instance of the top-level class.
NOTE: I think this convention should be reconsidered. The code of ViX evolved without considering something such as inheritance should be necessary, and that is obviously wrong. There must be better ways to do inheritance in C.
This convention is not perfect, and I know it. Please feel free to extend this list with all things that should be improven in order to make ViX easier to read (and maintain).
- Inheritance (see above)