Difference between revisions of "Tutorial tour"
m (s/LibertyEiffel/Liberty Eiffel/) |
|||
(5 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
Welcome to the guided tour of the tutorial! |
Welcome to the guided tour of the tutorial! |
||
− | All the classes in the tutorial are provided with your |
+ | All the classes in the tutorial are provided with your Liberty Eiffel installation, in the <code>tutorial</code> directory. |
=== Easy starting: Hello World! === |
=== Easy starting: Hello World! === |
||
Line 13: | Line 13: | ||
|- |
|- |
||
|<code>se</code> |
|<code>se</code> |
||
− | |the front-end tool for the |
+ | |the front-end tool for the Liberty Eiffel compiler |
|- |
|- |
||
|<code>c</code> |
|<code>c</code> |
||
Line 42: | Line 42: | ||
* knight.e |
* knight.e |
||
* pyramide.e and pyramide2.e |
* pyramide.e and pyramide2.e |
||
− | * gcd |
||
* hanoi |
* hanoi |
||
* parking |
* parking |
||
Line 58: | Line 57: | ||
=== Manifest notations === |
=== Manifest notations === |
||
− | + | Liberty Eiffel comes with a big set of available datatypes. Famous examples as INTEGER, BOOLEAN, CHARACTER and STRING. For those (and also many collection types) there is the possibility to directly denote them in the program code, using the notations |
|
123 |
123 |
||
True, False |
True, False |
||
Line 81: | Line 80: | ||
The visibility of these variables is limited to the method they are defined in and they do not keep their value from one execution of that routine to another. Assignment is done by the assignment operator ":=" which changes the variable (or let's say writable entity) on the left side to the value of the expression on the right side. In case of the "Hello World!" assignment a new object of type STRING is created on the heap, initialized to the text "Hello World!" and a link to this object is stored in the local variable s. |
The visibility of these variables is limited to the method they are defined in and they do not keep their value from one execution of that routine to another. Assignment is done by the assignment operator ":=" which changes the variable (or let's say writable entity) on the left side to the value of the expression on the right side. In case of the "Hello World!" assignment a new object of type STRING is created on the heap, initialized to the text "Hello World!" and a link to this object is stored in the local variable s. |
||
+ | |||
+ | === Loops === |
||
+ | In Eiffel we have exactly one construct to do something repeatedly, so no need to learn about for, do-while, while, anyhow, one is sufficient: |
||
+ | from |
||
+ | -- initialization |
||
+ | invariant |
||
+ | -- what shall stay true during repetition |
||
+ | variant |
||
+ | -- non-negative, but decreasing numeric value |
||
+ | until |
||
+ | -- termination condition |
||
+ | loop |
||
+ | -- what to do several times |
||
+ | end |
||
+ | |||
+ | Note, that the termination condition is an expression of type BOOLEAN and the loop body is executed until the condition evaluates to True, which differs in the logic from e. g. the loop constructs in C. |
||
+ | |||
+ | The most strange things for newcomers are probably the [https://en.wikipedia.org/wiki/Loop_invariant invariant] and the [https://en.wikipedia.org/wiki/Loop_variant variant]. While the first is a BOOLEAN condition, that stays true for every iteration, the latter is an INTEGER value which decreases with every iteration and always stays positive and therefore shows that the loop terminates. Both are optional and are not used very often in practice, even though they are essential in case we want to prove a program to be totally correct (and therefore terminates). I fear, that these formal loop assertions stay more or less unused until a formal verification tool is able to take real benefit from them. |
||
+ | |||
+ | See tutorial/loops.e for an example of the Greatest Common Divider algorithm to show the usage of the loop. |
||
=== Input-output === |
=== Input-output === |
||
+ | |||
− | * io |
||
+ | ==== io cluster ==== |
||
+ | |||
+ | The input-output cluster is made up of several parts. |
||
+ | |||
+ | The io/basic subcluster contains the staples of |
||
+ | |||
+ | * the definitions of standard input and output streams, [[library_class:STD_INPUT|STD_INPUT]] and [[library_class:STD_OUTPUT|STD_OUTPUT]] that are available to all classes. In fact [[library_class:ANY|ANY]] offers those features: |
||
+ | ** io: [[library_class:STD_INPUT_OUTPUT|STD_INPUT_OUTPUT]] -- Handle to standard file setup. |
||
+ | ** std_input: [[library_class:STD_INPUT|STD_INPUT]] -- The standard input stream |
||
+ | ** std_output: [[library_class:STD_OUTPUT|STD_OUTPUT]] -- The standard output stream |
||
+ | ** std_error: [[library_class:STD_ERROR|STD_ERROR]] -- The standard error stream |
||
+ | ** standard_streams: [[library_class:STANDARD_STREAMS|STANDARD_STREAMS]], a singleton that allows to redirect std_input_stream, std_output_stream as well as std_error_stream. |
||
+ | |||
+ | Beyond this standards streams that are available to all processes you can get read files in the operative file system using an [[library_class:INPUT_STREAM|INPUT_STREAM]] using [[library_class:BINARY_FILE_READ|BINARY_FILE_READ]] to read a binary file or [[library_class:TEXT_FILE_READ|TEXT_FILE_READ]] to read a text file. |
||
+ | Similarly, to write a file you use an [[library_class:OUTPUT_STREAM|OUTPUT_STREAM]] such as [[library_class:BINARY_FILE_WRITE|BINARY_FILE_WRITE]] for binary files or [[library_class:TEXT_FILE_WRITE|TEXT_FILE_WRITE]] for text files. |
||
+ | |||
+ | [[library_class:READLINE_INPUT_STREAM|READLINE_INPUT_STREAM]] is an input stream where the data is read from Command Line Interface (CLI) using the GNU readline library. You probabily have already used this library without knowing as it is used by several programs as at the time this notes has been written almost nine hundred packages in Debian use a version of readline |
||
+ | |||
+ | You may have noticed that Eiffel uses streams to access files. This is a much more flexible way to access data. In fact when you use an [[library_class:INPUT_STREAM|INPUT_STREAM]] the actual data can come from plain files, or from a string with [[library_class:STRING_INPUT_STREAM|STRING_INPUT_STREAM]] or any classes that conforms to and INPUT_STREAM, or more properly any live type that is a proper heir of INPUT_STREAM, such as BINARY_INPUT_STREAM, EZMQ_SOCKET_INPUT (a sockect messaging library), FILTER_INPUT_STREAM{ (put references to filters and explaiin BASE64_INPUT_STREAM, HTTP_CLIENT_INPUT_STREAM, MONITORED_INPUT_STREAM, QUOTED_PRINTABLE_INPUT_STREAM, TEMPLATE_INPUT_STREAM |
||
+ | ), TERMINAL_INPUT_STREAM. |
||
+ | |||
+ | Mostly for testing purposes there are also [[library_class:NULL_INPUT_STREAM|NULL_INPUT_STREAM]], a "null" stream provides an unbroken sequence of zero, like /dev/zero does on Unix and |
||
+ | [[library_class:NULL_OUTPUT_STREAM|NULL_OUTPUT_STREAM]] that swallows any character like /dev/null does on Unix. |
||
+ | |||
+ | |||
* directory |
* directory |
||
* basic_directory? |
* basic_directory? |
Latest revision as of 21:26, 14 June 2016
Welcome to the guided tour of the tutorial!
All the classes in the tutorial are provided with your Liberty Eiffel installation, in the tutorial
directory.
Easy starting: Hello World!
To compile the program, go to the LibertyEiffel/tutorial
directory and execute the command:
se c HELLO_WORLD make -o hello
The meaning of the command is
se
|
the front-end tool for the Liberty Eiffel compiler |
c
|
the tool invoked by se for compile into an executable
|
HELLO_WORLD
|
the class of which an object is created (you may also write it in lower-case, or use its filename with the .e extension) we call it root class, as this is the root of the programs object tree
|
make
|
the creation procedure of the HELLO_WORLD class to call
|
-o hello
|
generates an executable with the name hello (linux) or hello.exe (windows) |
The command produces an executable, usually hello
or hello.exe
depending on the system. After compiling is finished, you can run the executable.
This unavoidable program is in the file hello_world.e
and lets you grasp the basic concepts of Eiffel. Those concepts are:
- Everything is a class. In Eiffel, outside classes there is no salvation.
- The program starts by creating an object (of the root class) and initializing it by execution of the given root creation procedure. Here, the
make
feature in the classHELLO_WORLD
. - Each file is named after the name of the class it contains, in lower-case, with the
.e
extension. - Each class comes with a set of features, all its attributes and methods which come in form of functions (if they return a result) or procedures (in case they just 'do' something)
- Note the special object
io
that allows you to write text on the standard output. We will see that it also lets you read data. - For the Eiffel syntax, look here.
Please take a look at the following examples in the tutorial folder to see some classical example programs (some of them are in organized in folders for better overview)
- fibonacci.e
- knight.e
- pyramide.e and pyramide2.e
- hanoi
- parking
- triangle
To compile the other samples you must obviously modify the compiler command to give another root class .
Some important concepts
Comments
As in every programming language there is the possibility to write comments into the source code, which do not have any effect for the final program, but are for the developer or reader of the source code to get an understanding of the ideas and algorithms behind the code. A comment in Eiffel starts with the sequence of a couple of minus signs and is terminated by a newline (RETURN).
-- this is a comment in Eiffel a := b + 3 -- comments are also allowed after some code
Manifest notations
Liberty Eiffel comes with a big set of available datatypes. Famous examples as INTEGER, BOOLEAN, CHARACTER and STRING. For those (and also many collection types) there is the possibility to directly denote them in the program code, using the notations
123 True, False 'a' "STRING"
See tutorial file manifest_notation.e for an example with nearly all options to define objects by manifest notations.
Everything is an Object
As mentioned above, in Eiffel every useful thing is an object. There are two different kinds of objects: expanded objects and referenced object. Expanded objects are passed by value, while reference objects are - who guesses - passed by reference. In case you write 7 in the source code this is a shorthand for an instance of the expanded type INTEGER and therefore it is an expanded object. Whenever you assign it to a variable or pass it to another feature it gets copied. A STRING object - e. g. denoted by "Hello World!" in the source code is a reference object, created implicitly by the compiler, allocated on the heap and passed by reference.
Local variables and Assignments
Every routine may define variables in a "local block" before its body (which start with the keyword do):
make local a: INTEGER s: STRING do a := 5 a := a + 1 s := "Hello World!" end
The visibility of these variables is limited to the method they are defined in and they do not keep their value from one execution of that routine to another. Assignment is done by the assignment operator ":=" which changes the variable (or let's say writable entity) on the left side to the value of the expression on the right side. In case of the "Hello World!" assignment a new object of type STRING is created on the heap, initialized to the text "Hello World!" and a link to this object is stored in the local variable s.
Loops
In Eiffel we have exactly one construct to do something repeatedly, so no need to learn about for, do-while, while, anyhow, one is sufficient:
from -- initialization invariant -- what shall stay true during repetition variant -- non-negative, but decreasing numeric value until -- termination condition loop -- what to do several times end
Note, that the termination condition is an expression of type BOOLEAN and the loop body is executed until the condition evaluates to True, which differs in the logic from e. g. the loop constructs in C.
The most strange things for newcomers are probably the invariant and the variant. While the first is a BOOLEAN condition, that stays true for every iteration, the latter is an INTEGER value which decreases with every iteration and always stays positive and therefore shows that the loop terminates. Both are optional and are not used very often in practice, even though they are essential in case we want to prove a program to be totally correct (and therefore terminates). I fear, that these formal loop assertions stay more or less unused until a formal verification tool is able to take real benefit from them.
See tutorial/loops.e for an example of the Greatest Common Divider algorithm to show the usage of the loop.
Input-output
io cluster
The input-output cluster is made up of several parts.
The io/basic subcluster contains the staples of
- the definitions of standard input and output streams, STD_INPUT and STD_OUTPUT that are available to all classes. In fact ANY offers those features:
- io: STD_INPUT_OUTPUT -- Handle to standard file setup.
- std_input: STD_INPUT -- The standard input stream
- std_output: STD_OUTPUT -- The standard output stream
- std_error: STD_ERROR -- The standard error stream
- standard_streams: STANDARD_STREAMS, a singleton that allows to redirect std_input_stream, std_output_stream as well as std_error_stream.
Beyond this standards streams that are available to all processes you can get read files in the operative file system using an INPUT_STREAM using BINARY_FILE_READ to read a binary file or TEXT_FILE_READ to read a text file. Similarly, to write a file you use an OUTPUT_STREAM such as BINARY_FILE_WRITE for binary files or TEXT_FILE_WRITE for text files.
READLINE_INPUT_STREAM is an input stream where the data is read from Command Line Interface (CLI) using the GNU readline library. You probabily have already used this library without knowing as it is used by several programs as at the time this notes has been written almost nine hundred packages in Debian use a version of readline
You may have noticed that Eiffel uses streams to access files. This is a much more flexible way to access data. In fact when you use an INPUT_STREAM the actual data can come from plain files, or from a string with STRING_INPUT_STREAM or any classes that conforms to and INPUT_STREAM, or more properly any live type that is a proper heir of INPUT_STREAM, such as BINARY_INPUT_STREAM, EZMQ_SOCKET_INPUT (a sockect messaging library), FILTER_INPUT_STREAM{ (put references to filters and explaiin BASE64_INPUT_STREAM, HTTP_CLIENT_INPUT_STREAM, MONITORED_INPUT_STREAM, QUOTED_PRINTABLE_INPUT_STREAM, TEMPLATE_INPUT_STREAM ), TERMINAL_INPUT_STREAM.
Mostly for testing purposes there are also NULL_INPUT_STREAM, a "null" stream provides an unbroken sequence of zero, like /dev/zero does on Unix and NULL_OUTPUT_STREAM that swallows any character like /dev/null does on Unix.
- directory
- basic_directory?
Arguments
print_arguments.e
Feature calls
Contracts
Contracts are the main reason why Eiffel is superior to many other languages... ...
Garbage collection
Eiffel is garbage collected. That means, the objects created on the heap will automatically be freed after they lost reachability from the rest of the executing program.
ACE files
Collections
including iterator and sorting
Downcasting
downcasting.e
To go further
Agents
... and tuples
external
cecil
Memory management
memory
Extension libraries
Random
Date & time
Storable
Sequencer
Vision
visiopn, signal