Capsula is a simple, absolutely structured, type-safe, imperative, object-oriented and graphical computer programming language for expressing application software. It uses a subset of elements which are known from the Pascal family as well as from C family, especially from their most developed descendants Oberon, Java and C#.
To make it as simple and comprehensible as possible many unnecessary elements of its predecessors have been removed. Therefore, the cyclomatic complexity of Capsula itself and the software programmed with Capsula is very low and this significantly facilitates the verification of software. Nevertheless, its expressiveness is powerful enough to realise projects of any size and complexity.
Capsula supports runtime efficient static data types as well as dynamic data types, which allow powerful data structures. It can be transformed to source code of other programming languages, directly be interpreted in runtime environments or compiled to portable meta code or executable code.
Capsula is in the public domain and it subsumes many good and well-established programming elements, but it does not reinvent the wheel. It is rather a vehicle that is
common enough to run safely with parts of different manufacturers
smooth enough to safe resources
robust enough to allow off-road excursions safely
cheap enough to be used for public transport
small enough to be mobile
easy enough to construct scale models
solid enough to provide for easy to maintain endurance
inert enough to keep developers on rail track
safe enough to achieve short braking distances
The elements of Capsula are rectangular and have two table columns in their definition giving the name and the description of an element:
Element name
Element description
The description often fits to a simple rectangle, but it may be sub-structured with smaller rectangles. The description has to be read and will be processed and executed firstly from left to right and secondly from top to bottom.
The element description is given according to the Extended Backus-Naur-Form (EBNF) in this document. Capsula code can easily be saved in and loaded from xml-files.
An identifier must start with a letter and can only contain letters and digits. Identifiers are defined using the Latin1 extension of the ASCII character set, which is defined in the standard ISO/IEC 8859-1.
Interfaces are a major and unique concept for defining the name and the scope of main Capsula elements such as packages, modules, signatures, data types or commands.
Interface
Identifier "is" Visibility
Visibility
"Private" | "Public"
The visibility is expressed by a modifier which allows adjusting the scope of an element which is described by the interface. A private element is only visible in the unit where it is declared, a public element can be accessed from any other unit within the scope by qualified reference.
Signatures are a major and unique concept of Capsula for defining the interface and the data type of constants and of variables as well as of functions and of formal parameters of functions and commands.
Signature
Interface Type
For static data types the default values of any elements are the constants "False", "0", "0.0" or Nil (empty string), and for dynamic dara types the default value is always the constant Nil (null pointer).
Unit | Constant | Type | Variable | FormalParameter | Command | Function | ActualParameter | Statement | Case
Every Capsula list element has exactly one successor and one predecessor element. The predecessor of the first element and the successor of the last element are Nil. List elements are active by default but any list element can be deactivated by the programmer for code testing.
Furthermore, there is a text comment possible for every Capsula element. A comment is always a character string and the default value of the comment is an empty string.
ListElement
Comment
String
isActive
Boolean
Predecessor
ListElement
Successor
ListElement
For reasons of simplicity and better readability these common sections of all Capsula elements are omitted in the following definitions.
Usually units will be stored as a whole in separate files or separate database sections, and therefore, these units can be considered as storable and basic Capsula elements (EOF = end of file):
Capsula
Unit
EOF
Unit
Package | Module
Package
"Package" Interface
{Unit}
Packages can be defined recurrently, but they must not contain themselves.
Furthermore, they must contain either only sub packages or only modules. A unit which is belonging to a certain package cannot belong to another package, too.
The concept of the module may be interpreted as a unit of compilation.
Module
"Module" Interface
{Constant}
{Type}
{Variable}
{Command}
{Function}
Init
Exit
All constants, types, variables, commands and functions of a module are static. Dynamic programming is fully supported by using dynamic data types such as arrays and classes.
Init
"initModule"
{Statements}
The statements of the element labelled initModule are executed directly after all imported modules and the module itself are loaded to the run time system. They can be used to initialise the variables of a module and to execute any other statements.
Exit
"exitModule"
{Statements}
The statements of the element labelled exitModule are executed directly befor the module itself is removed from the run time system. They can be used to finalise the variables of a module and to execute any other statements.
Basic data types have reserved names and they are inherently public to all elements of Capsula. Since these types are static, they can be implemented very efficiently, but basic types also can be used in any dynamic types.
BasicType
Boolean | Integer | Real
Booleans have one bit which might be either "False" or "True".
Integers have one bit for the sign and 63 bits for the absolute value. Therefore, the extreme values are:
Constant MinimumInteger is Public Integer
Constant MaximumInteger is Public Integer
Number
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
ConstantIntegerExpression
[-]Number{Number}
Reals are defined according to the binary 64-bit standard of IEEE 754. Integer numbers can always be used as Real numbers.
Complex data types are referenced by qualified identifiers and may use qualified identifiers to denote other types themselves. Complex types are very useful to contain data with complex data structures.
A class comprises data (also called attributes or class variables) as well as subroutine code (also called methods) at the same time which are bound to the appropriate class. Within a class the attributes are represented by global variables and the methods are represented by appropriate commands (without return value) and functions (with return value).
Dynamic classes can be used to inherit visible attributes and visible methods from dynamic parent classes or to pass visible attributes and visible subroutines on to child classes.
Classes without methods can be considered as composite data records with a dynamic memory address that has to be allocated by the programm code.
If classes are not used for the inheritance of child classes it would be more useful and efficient to decleare these classes as static and final classes (similar to classical program modules).
Class
Extendibility ["extension of" ParentIdentifier]
{Constant}
{Variable}
{Command}
{Function}
The modifier "Flexibility" is mandatory.
Classes are always dynamic and can reference themselves in recursive declarations.
Extendibility
"Final" | "Extensible" | "Abstract"
The modifier "Extendibility" is mandatory. A final class cannot be extended or be abstract. An abstract class always is extensible.
ParentIdentifier
QualifiedIdentifier
If the parent identifier is the class type AnyClass, which can be considered as the root class type of Capsula, then the appropriate class denotes a novel class. If a novel class is final, then it is called an elementary class, which due to the possibility of declaring not only attributes but also methods is a conceptual extension of simple data records respectively data structures.
There is a maximum of one parent identifier for a particular class, and therefore, multiple interface inheritance or implementation inheritance is neither intended nor possible nor necessary.
If classes are declared as dynamic types their attributes can be instances of or can use references to the class they belong to (recursive data structure).
An initialisation command can be bound to a class and should be called to initialise the attributes of the class (some programmers call it constructor). Usually initialisation commands have an arbitrary number of parameters, which are static for a particular class. The initialisation command of a parent class can be called within the statements of the classes’ initialisation command and therefore, it is useful to use the name of the class in the name of the initialisation command to allow easy recognition and determination of different initialisation commands. Also initialisation commands can be inherited by parent classes and therefore, they can be overwritten but not overloaded in child classes.
All attributes and methods are directly bound to the class and can be overwritten in extended classes, but cannot be overloaded. Therefore, their names and parameter lists are constant (this applies for the signatures of functions, too) and all methods are unique for the class where they are declared as well as for any of their child classes. Nevertheless, methods of the parent classes which are not overwritten by a child class can be called for any instance of a child classes, too.
The program has to create instances of dynamic classes by calling the inherently existing newClass-function which has one parameter which denotes the name of the appropriate class:
ClassInstanceDesignator
Designator
ClassTypeDesignator
QualifiedIdentifier
ClassCreation
ClassInstanceDesignator "←"
"→" ClassTypeDesignator.newClass
The class type designator has to denote a class type by a qualified identifier and the result of the call of the parameterless newClass-function has to be assigned to an instance designator of this class type.
Arrays denote linear lists of elements of the same data type. Its elements can be accessed by non-negative integer expressions which are called indexes. The first element is always represented by the index zero.
Array
"Array" [length] "of" (BasicType | ComplexType)
length
ConstantIntegerExpression
Capsula arrays are always one-dimensional and as structured types they cannot contain themselves but they may contain dynamic elements. The length of an array is at least one and it can be get by calling its read-only variable ArrayDesignator.length. An array is always a dynamic data type even if its length is never changed after its first declaration because this does not affect the efficiency of the implementation.
An array with the length zero (the element "length" was omitted in the declaration) is called empty array and it has the value Nil. Empty arrays can be used to declare open arrays. An instance of an open array is created by calling the newArray-function together with a length greater than zero as an integer parameter.
ArrayDesignator
Designator
ArrayTypeDesignator
QualifiedIdentifier
ArrayCreation
ArrayDesignator "←"
"→" ArrayTypeDesignator.newArray
length
The array type designator has to denote an array type by a qualified identifier and the result of the call of the newArray-function has to be assigned to an array designator of this array type.
Strings are character strings of any length and they are a fundamental data type for the software communication with human beings and all Unicode characters are allowed in strings. An empty string is always represented by the value Nil. Internally strings can be represented by arrays of integer numbers, but the user does not have direct access to the array elements.
Commands as well as functions use formal parameters which are variables for exchanging data with the calling statements.
FormalParameter
"Parameter" Signature
Private parameters can be considered as input parameters (call by value) and public parameters can be considered as variable or output parameters (call by reference). The definition of formal parameters is a constant list and is not affected or changed by inheritance, since Capsula does not allow overloading commands or functions. Therefore, formal parameters are not part of the interface of the commands or the signatures of functions, but of the body:
Body
{FormalParameter}
{Constant}
{Variable}
{Statement}
The input parameters, constants and variables of the body are always Private, and therefore, they only can be accessed and changed locally within the statements of the body.
A function can be called in an assignment statement as an expression with a result.
A valid return value has to be assigned to a designator which is identical to the identifier of the function in the last statement of the body of the function.
Designators are used to denote variables if complex data types and the expression Nil can be used to denote empty character strings or arrays or undefined instances of classes.
Booleans, integer and real numbers as well as strings can be used as operands.
The IntegerIsEqual-operator returns True if the two integer operands have the same values and False otherwise.
The IntegerIsNotEqual-operator returns False if the two integer operands have the same values and True otherwise.
The IntegerIsLess-operator returns True if the first integer operand is less than the second integer operand and False otherwise.
The IntegerIsLessOrEqual-operator returns True if the first integer operand is less than or equal the second integer operand and False otherwise.
The IntegerIsGreaterOrEqual-operator returns True if the first integer operand is greater than or equal the second integer operand and False otherwise.
The IntegerIsGreater-operator returns True if the first integer operand is greater than the second integer operand and False otherwise.
The difference between commands and functions is that the former do not have return values which have to be assigned to a desigator. Commands are called as a statement and functions are called as an expression within an assignment statement. Both, commands and functions, may use parameters to exchange data with the calling statement.
ActualParameter
Expression
The actual parameters of a command or function call must have exactly the same number and assignment compatible data types as the formal parameters of the called command or function.
Since function calls are not considered as expressions in Capsula, actual parameters cannot be results of function calls directly, because nested function calls may cause side effects which depend on the sequence of the actual parameters. Therefore, the results of function calls have to be assigned to designators which then can be used as actual parameters of a command or function call.
Call
"→" Designator
{ActualParameter}
A method or the init-command of a parent class can be called within a method or the init-command of a child class (super call).
If the Halt-command is called, the program execution stops at this particular point of the statement sequence. The Halt-command has exactly one integer parameter.
HaltCommandCall
"→Halt" | IntegerExpression
The value of the integer expression can be used in order to specify different HALT-statements or in order to distiguish different program states at a halt point of the execution.
The value of an integer variable (also within arrays or classes) can be decreased by one by the Decrease-command and increased by one by the Increase-command. Both commands have exactly one integer parameter.
Any expression can be assigned to a designator which is assignment compatible to the expression.
FunctionCall
Call
Functions only can be called within assignments. The result of a function has to be assigned to the designator of the assignment. Therefore, the result of the appropriate function also must be assignment compatible to the data type of the designator.
Within the statement sequence of a type case the variable denoted by the designator will be treated as a variable of the appropriate constant type of the type case denoted by the identifier.
Pre-test and post-test loop conditions are locally linked to the loop as Boolean operands. These loop conditions have to be considered as local and private variables of the loop, and therefore, they cannot be accessed outside of the Loop statement.
LoopCondition
"←" BooleanOperand
The statement sequence of a loop statement will only be invoked and repeated as long as the loop condition is "True". The pre-test loop condition has to be given in the first statement of the loop. The post-test loop condition has to be given as the last statement of the loop.
Loop
"While" LoopCondition "→"
{Statement}
LoopCondition
If the pre-test loop condition is set to "True", then the statements within the loop will be executed at least once. If the pre-test condition is set to "False", then the statement sequence will not be executed at all.
The quasi standard programme "HelloWorld" can be graphically expressed in Capsula like this:
The command can be invoked within the scope of the package "Examples" by calling the symbol Examples.HelloWorld.printHelloWorld and will print the string "Hello World !" to the standard output of the system.
If there are no parameters in a command, the appropriate frame is kept empty in the code. The constant string "OutputString" is private and can only be used within the subroutine of the command "printHelloWorld". Since strings do not need delimiters in Capsula such as quotation marks, the background rectangle of the string is marked by a colour. Because there are no local variables in the subroutine, the appropriate frame is hidden.
All sub frames optionally can be edited separately in a new window by clicking on the the hyperlink of the appropriate identifier in the left upper field of the sub frame, where the sub frame always is extended to the uttermost right edge of the structure. Clicking on "Hello World" produces a new window like this for example:
All sub frames can be reduced in the editor to one line or extended with clicking on the name of the appropriate Capsula element. For example clicking on "Module" produces the following display with the collapsed frame of the module:
The definition view of a Capsula element only shows all public items:
A recursively defined function factorial in a module IntegerMath of the package Examples that computes the factorial of an integer number could be defined like this:
If you call the function factorial with the integer parameter x with the value 6 you will get returned the integer value factorial 720.
The naming of Capsula refers to the fact that it strictly and strongly supports the principles of encapsulation.
But at the same time the name Capsula is a hidden dedication to several programming languages which have influenced Capsula. The name Capsula contains all letters of the names of the programming languages APL, C and Pascal. Furthermore, it ends with "-ula" such as the programming language Modula and it has an "a" at the second and at the last position such as the programming language Java.
The seed of the idea to invent Capsula was a interview of Niklaus Wirth at the IEEE Computer Society for the medium Computing Now in 2010. He was asked:
„You mean they should go back and start designing a new language.“,
and he responded:
„Well, they could go back to Oberon and start there and improve it.“
Antoine de Saint-Exupéry has written in the third chapter L'Avion of his book Terre des hommes:
„Il semble que la perfection soit atteinte non quand il n'y a plus rien à ajouter, mais quand il n'y a plus rien à retrancher.“
(„It seems that perfection is not attained when there is nothing more to add, but when there is nothing more to remove.“)
Johann Wolfgang von Goethe has written the poem Das Sonett which ends with these six lines:
So ists mit aller Bildung auch beschaffen:
Vergebens werden ungebundne Geister
Nach der Vollendung reiner Höhe streben.
Wer Großes will, muß sich zusammenraffen;
In der Beschränkung zeigt sich erst der Meister,
Und das Gesetz nur kann uns Freiheit geben.
(That is the apperance of all education:
Free spirits will aspire in vain
to the pure summit of accomplishment.
The one who wants great things, has to gather himself;
The master presents himself by limitation,
And only law can give us freedom.)
Therefore, the stepwise refinement during the development of Capsula often was rather a stepwise coarsening respectively simplification than a refinement. But this was always done without removing any essential power of the programming language.