When you contribute new code or make changes to existing code, please consider the following guidelines.
A high-level FieldTrip function always should behave like this
[outputargs] = ft_functionname(cfg, inputargs)
where some functions might not need inputargs and some functions might not return outputargs.
The function should always start with a help section, that explains the purpose of the function, the type of input data that it expects, the type of output data that it will produce and the configurable options that the user has to control the behaviour of the function.
The easiest way to get started with writing a new high-level FieldTrip function is to take a close look at ft_examplefunction, which is located in FT's core (root) directory. (Note: this is true as of Feb 11, 2011.) It shows the best practices that one should adhere to concerning input and output structure and data handling. Also, it demonstrates how one should document the function according to FT standard guidelines.
Any new configuration option should have a default set at the beginning of the function. If you don't know a good default value, you should specify the default value as empty, i.e. cfg.newoption = [].
If you add a configuration option, you should check in the configuration index whether a cfg option with similar functionality already exist in another function. Use identical names for identical functionality and try to keep the help similar if possible.
Whenever you rename a configuration option, you have to ensure backward compatibility with the end-users' scripts that they have carefully crafted. Forcing the users to update the scripts every time we change something will scare them away. That is why you should use
cfg = ft_checkconfig(cfg, 'renamed', {'oldoption', 'newoption'})
or
cfg = ft_checkconfig(cfg, 'renamedval', {'option', 'oldval', 'newval'})
This will ensure that the user script will continue to work. Furthermore, he/she will get warning or error (depending on whether cfg.checkconfig is 'silent', 'loose' or 'pedantic').
If you remove a configuration option from a function, you should ensure that the user of that function becomes aware of it. Sending an email to the mailing list is one option (and in general good), but it might be that he/she is not subscribed to the mailing list. That is why you should also add the following to the function
cfg = ft_checkconfig(cfg, 'forbidden', 'oldoption')
In case the user still specifies the option, he/she will get warning or error (depending on whether cfg.checkconfig is 'loose' or 'pedantic').
SVN log entries should describe the change to the file or files. The log message should allow an end-user to realize that a recent change in the code may relate to the changed behaviour that he/she observes. The log message should also allow another developer that is familiar with the particular code to understand why the code was changed, and what part of the code is changed.
Log messages don't have to be long, but they have to be clear to the intended audience: end-users and colleague developers. Log messages should also be clear for yourself, because sometimes you'll have to go back in a function to fix problems that were introduced by your own previous change.
To allow better human and machine readable changelogs, please start your log message with a single descriptive word and a hyphen to separates it from the actual description. Whenever applicable you should use the description “bugfix”, “enhancement”, “documentation”, “restructuring”.
Examples of good and useful log messages are
documentation - changed the documentation, no change to the code enhancement - added support for the new cfg.whatever option restructuring - changed the structure of the code, instead of .... it now works like ... bugfix - fixed a problem in xxx, in case of ... it did ..., whereas it should be doing ... bugfix - fixed the problem described in http://bugzilla.fcdonders.nl/show_bug.cgi?id=50
Examples of bad log messages are
<empty> made a change in this function lot of small changes fixed a bug
In FieldTrip the interface towards the user is controlled by making only those functions publicly available that the end-user is supposed to call from the command-line or from a Matlab script. Those functions are public and should be in the main directory or in one of the module directories.
Low-level functions that are only supposed to be called by other FieldTrip functions but not by the end-user should be in the private directory.
Functions in a module, i.e. sub-directory, should not be calling any FieldTrip functions at a higher level. E.g. a function like fileio/xxx.m should only call other functions in fileio, in fileio/private or in an external toolbox. If you don't know how to work with svn autosycn, please ask the senior developers.
This requirement on the dependencies ensures the modular design.
Generally functions (i.e. in the plotting directory) have optional arguments as a pair of inputs describing the name of one property and its value. These arguments have to be handled at the very beginning inside the function, by setting a default value, like this:
function ft_plot_mesh(bnd, varargin)
...
% get the optional input arguments
facecolor = keyval('facecolor', varargin); if isempty(facecolor), facecolor='white';end
vertexcolor = keyval('vertexcolor', varargin); if isempty(vertexcolor), vertexcolor='none';end
The function keyval is specific to check syntactic consinstency of the arguments, and the if statement checks if the variable has been specified, otherwise assigns a default value. In this way the variables which are used in the function are always correctly initialized.
Since we support FieldTrip on all currently popular platforms regarding hardware and software, we have to create executables for all platforms that we can. If an executable cannot be compiled on a particular platform, e.g. because it depends on windows specific DLLs, then you of course don't have to bother.
Ensuring that all executables can co-exist on all platforms (and especially on the unix base platforms) means that they should have unique file names. The choice for that is based on the specification according to the MATLAB function “computer”, i.e.
>> help computer
COMPUTER Computer type.
C = COMPUTER returns string C denoting the type of computer
on which MATLAB is executing. Possibilities are:
ISPC ISUNIX ISMAC
32-Bit Platforms
PCWIN - Microsoft Windows on x86 1 0 0
GLNX86 - Linux on x86 0 1 0
MACI - Apple Mac OS X on x86 0 1 1
64-Bit Platforms
PCWIN64 - Microsoft Windows on x64 1 0 0
GLNXA64 - Linux on x86_64 0 1 0
SOL64 - Sun Solaris on SPARC 0 1 0
MACI64 - Apple Mac OS X on x86_64 0 1 1
[C,MAXSIZE] = COMPUTER also returns integer MAXSIZE which
contains the maximum number of elements allowed in a matrix
on this version of MATLAB.
[C,MAXSIZE,ENDIAN] = COMPUTER also returns either 'L' for
little endian byte ordering or 'B' for big endian byte ordering.
HPUX, HP700, ALPHA, IBM_RS, SGI, and Mac for PowerPC are no
longer supported.
See also ispc, isunix, ismac.
The binaries for the different versions of the unix platforms (Linux, OS X) should have an extension corresponding to the computer type, e.g. the buffer executable would be named
Note that on Windows the executable is required to have the file extension “exe”. In general it is sufficient to only provide a 32-bit version of the executable. For 64-bit Windows there is no convention yet.
FieldTrip of course depends on MATLAB, but there are additional requirements, such as operating systems (for mex files) and external toolboxes. We want to develop FieldTrip such that it can be used by as many people as possible, which means that we want to control and minimize the additional requirements
Please consider the general requirements when extending or changing the FieldTrip code. Keep in mind that FieldTrip should not only run on the latest and greatest MATLAB version that you happen to have installed on your personal “supercomputer”, but also on the more modest computers of many other people with other (older or newer) MATLAB versions and operating systems.
Although you may be developing FieldTrip on the latest MATLAB version, we try to support it for previous MATLAB versions up to five years old.
| version number | release name | release date |
|---|---|---|
| MATLAB 7.13 | R2011b | 13 Aug 2011 |
| MATLAB 7.12 | R2011a | 08 Apr 2011 |
| MATLAB 7.11 | R2010b | 03 Sep 2010 |
| MATLAB 7.10 | R2010a | 05 Mar 2010 |
| MATLAB 7.9 | R2009b | 04 Sep 2009 |
| MATLAB 7.8 | R2009a | 06 Mar 2009 |
| MATLAB 7.7 | R2008b | 09 Oct 2008 |
| MATLAB 7.6 | R2008a | 01 Mar 2008 |
| MATLAB 7.5 | R2007b | 01 Sep 2007 |
| MATLAB 7.4 | R2007a | 01 Mar 2007 |
| MATLAB 7.3 | R2006b | 03 Aug 2006 |
| MATLAB 7.2 | R2006a | 27 Jan 2006 |
| MATLAB 7.1.0 | R14-SP3 | 02 Aug 2005 |
| MATLAB 7.0.4 | R14-SP2 | 29 Jan 2005 |
| MATLAB 7.0.0 | R14 | 06 May 2004 |
| MATLAB 6.5.1 | R13-SP1 | 04 Aug 2003 |
| MATLAB 6.5.0 | R13 | 27 Jun 2002 |
To facilitate supporting older MATLAB versions, below we list some known incompatibilities:
Although a nested function has certain advantages, it makes maintaining the code more difficult. Furthermore, ft_preamble and eval are not fully compatible with nested functions.
It is annoying to get large svn diffs just because of changes in the whitespace. That is why all developers are encouraged to work with two spaces instead of tabs. In the MATLAB editor you can specify this in preferences→editor→tab, where you can specify “2” and “tab key inserts spaces”.
With Ctrl-A, Ctrl-I you can auto-indent the whole m-file and ensure that the horizontal whitespaces are consistent.
If you are unsure about the choices that you should make in developing new code or contributing to existing code, please ask one of the experienced developers for help. Robert, Jan-Mathijs, Ingrid and Saskia all have a good understanding of the FieldTrip programming philosophy.
Please also consider the documentation guidelines when making contributions to the FieldTrip project.
Share this page: