Update
This commit is contained in:
parent
201edec81b
commit
73fc5424ca
19 changed files with 1809 additions and 1767 deletions
|
@ -20,11 +20,27 @@ Remember, portability is about **making it easy for a programmer to take your pr
|
|||
|
||||
In your compiled programs **always make your own thin [I/O](io.md) abstraction, [decouple](coupling.md) your I/O libraries, separate [frontend](frontend.md) and [backend](backend.md)**. This is one of the most basic and most important things to do. Why? Well unless you're writing a library, you will need to use I/O (write out messages, draw to screen, create [GUI](gui.md), read keyboard commands, read from files, read from network, ...) so you will NEED to use some library for this (C [stdlib](stdlib.md), [SDL](sdl.md), OS [syscalls](syscall.md), [Xlib](xlib.md), ...) but you absolutely DON'T WANT this library to become a hard [dependency](dependency.md) of your program because if your program depends let's say on SDL, you won't be able to make your program run on platforms that don't have SDL. So the situation is that you HAVE TO use some I/O library but you don't want to become dependent on it.
|
||||
|
||||
The way to solve this is to create your own small I/O abstraction in your project, i.e. your own functions (such as `drawPixel`, `writeMessage`, `keyPressed`, `playSound`, `readFrile` etc.) for performing I/O, which you will use inside your main program. These functions will be defined in a small file which will basically be your own small I/O library just for your program. The functions you define there will then internally use functions of whatever underlying I/O system you choose to use at the time as your [frontend](frontend.md) (SDL, Xlib, SFML, ...); the important thing is that your main program code won't itself depend on the underlying system, it will only depend on your I/O abstraction, your own functions. Your custom I/O functions will depend on the underlying I/O system but in a way that's very easy to change -- let's say that your `keyPressed` function internally uses SDL's `SDL_GetKeyboardState` to read keyboard state. If you want to switch from using SDL to using a different frontend, you will only have to change the code in one place: in your I/O abstraction code, i.e. inside your `keyPressed` function. E.g. if you switch from SDL to SFML, you will just delete the code inside your `keyPressed` function and put in another code that uses SFML functions to read keyboard (e.g. the `isKeyPressed` attribute), and your whole code will instantly just work on SFML. In fact you can have multiple implementations of your functions and allow switching of different backends freely -- just as it is possible to compile a [C](c.md) program with any C compiler, you can make it possible to compile your program with any I/O frontend. If you used SDL's specific functions in your main code, you would have to completely rewrite your whole codebase if you wanted to switch away from SDL -- for this reason your main code must never directly touch the underlying I/O system, it must only do so through your I/O abstraction. Of course these principles may apply to any other thing that requires use of external libraries, not just I/O.
|
||||
The way to solve this is to create your own small I/O abstraction in your project, i.e. your own functions (such as `drawPixel`, `writeMessage`, `keyPressed`, `playSound`, `readFrile` etc.) for performing I/O, which you will use inside your main program. These functions will be defined in a small file which will basically be your own small I/O library just for your program. The functions you define there will then internally use functions of whatever underlying I/O system you choose to use at the time as your [frontend](frontend.md) (SDL, Xlib, SFML, ...); the important thing is that your main program code won't itself depend on the underlying system, it will only depend on your I/O abstraction, your own functions. Your custom I/O functions will depend on the underlying I/O system but in a way that's very easy to change -- let's say that your `keyPressed` function internally uses SDL's `SDL_GetKeyboardState` to read keyboard state. If you want to switch from using SDL to using a different frontend, you will only have to change the code in one place: in your I/O abstraction code, i.e. inside your `keyPressed` function. E.g. if you switch from SDL to SFML, you will just delete the code inside your `keyPressed` function and put in another code that uses SFML functions to read keyboard (e.g. the `isKeyPressed` attribute), and your whole code will instantly just work on SFML. In fact you can have multiple implementations of your functions and allow switching of different backends freely -- just as it is possible to compile a [C](c.md) program with any C compiler, you can make it possible to compile your program with any I/O frontend. If you used SDL's specific functions in your main code, you would have to completely rewrite your whole codebase if you wanted to switch away from SDL -- for this reason your main code must never directly touch the underlying I/O system, it must only do so through your I/O abstraction. Of course these principles may apply to any other thing that requires use of external libraries, not just I/O. Here is a small picture:
|
||||
|
||||
```
|
||||
WRONG CORRECT
|
||||
_______________ _______________
|
||||
| | | |
|
||||
| program | | program | backend
|
||||
|_______________| |_______________|
|
||||
_______________ _______________
|
||||
| | | |
|
||||
| librar(y|ies) | | abstraction | API
|
||||
|_______________| |_______________|
|
||||
_______________
|
||||
| |
|
||||
| librar(y|ies) | frontend
|
||||
|_______________|
|
||||
```
|
||||
|
||||
This is all demonstrated by [LRS](lrs.md) programs such as [Anarch](anarch.md) or [SAF](saf.md), you can take a look at their code to see how it all works.
|
||||
|
||||
Anyway the following is a simple [C](c.md) code to demonstrate the abstraction from an I/O system -- it draws a dithered rectangle to the screen and waits until the user pressed the `q` key, then ends. The main code is written independently of any I/O system and can use either C [stdlib](stdlib.md) (*stdio*, draws the rectangle to terminal with ASCII characters) or SDL2 (draws the rectangle to actual window) as its frontend -- of course more frontends (e.g. one using Xlib or SFML) can be added easily, this is left as an exercise :)
|
||||
Anyway the following is a simple [C](c.md) code to demonstrate the abstraction from an I/O system -- it draws a dithered rectangle to the screen and waits until the user pressed the `q` key, then ends. The main code is written independently of any I/O system and can use either C [stdlib](stdlib.md) (*stdio*, draws the rectangle to terminal with ASCII characters) or SDL2 (draws the rectangle to actual window) as its frontend -- of course more frontends (e.g. one using Xlib or SFML) can be added easily, this is left as an exercise :) Also here we have a single piece of code, in practice you'll probably want to put your backend in one file and then have each frontend in its own file; switching frontends will then be achieved by only changing one `#include`.
|
||||
|
||||
```
|
||||
#define SCREEN_W 80
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue