Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions doc/tutorial/01_introduction/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ this implies no copyright-obligations (however distributing SeqAn or an applicat
using it does, see [Copyright](https://docs.seqan.de/seqan3/main_user/about_copyright.html) and
[Citing](https://docs.seqan.de/seqan3/main_user/about_citing.html)).

You may ask why we do not use std::cout or std::cerr for console output.
Actually, for the given text it does not make a difference since seqan3::debug_stream prints to std::cerr as well.
You may ask why we do not use `std::cout` or `std::cerr` for console output.
Actually, for the given text it does not make a difference since `seqan3::debug_stream` prints to `std::cerr` as well.
However, the debug stream provides convenient output for SeqAn's types as well as widely used data structures
(e.g. std::vector), which is especially helpful when you debug or develop your program
(e.g., `std::vector`), which is especially helpful when you debug or develop your program
(that's where the name originates from).

\assignment{Assignment 1: Debug stream}
Write a program that creates a std::vector of type `int` and initialise the vector with a few values.
Then print the vector with seqan3::debug_stream. Does your program also work with std::cerr?
Write a program that creates a `std::vector` of type `int` and initialise the vector with a few values.
Then print the vector with `seqan3::debug_stream`. Does your program also work with `std::cerr`?
\endassignment
\solution
\snippet introduction_debug_stream.cpp debug
Expand Down Expand Up @@ -76,7 +76,7 @@ Some helpful tips when browsing our documentation:
[cookbook](https://docs.seqan.de/seqan3/main_user/cookbook.html). It is not structured and huge, but works
well if you do a key word search with `Ctrl+F`.

We recommend you to open the API documentation in separate browser tab s.t. you can easily switch back to the tutorial.
We recommend you to open the API documentation in a separate browser tab s.t. you can easily switch back to the tutorial.

If you have troubles or the documentation is missing some information, feel free to write to the developers
of SeqAn on [Github](https://github.com/seqan/seqan3/issues/new/choose) and ask your questions directly.
Expand Down Expand Up @@ -127,11 +127,11 @@ e.g. type templates are used like ordinary types in many situations (no `<>`).
We also always use `{}` to initialise objects and not `()` which is only used for function calls.
In general, the style should be much easier for newcomers.

## Avoid using namespace seqan3
## Avoid <code>using namespace seqan3</code>

In concordance with the [C++ Core guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rs-using),
we encourage you to avoid declaring `using namespace seqan3;`. This has the benefit of easily distinguishing
between `seqan3` features and standard C++ (`std`). The only exception are string literals, where we often use
between `seqan3` features and standard C++ (`std`). The only exceptions are string literals, where we often use
`using namespace seqan3::literals;` for convenience.

# The next tutorials
Expand Down
6 changes: 3 additions & 3 deletions doc/tutorial/02_argument_parser/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ We have separated the feature of parsing command line arguments to its own proje

### [![sharg_logo][sharg_logo_link]][sharg_link] The Sharg Parser

* Github Repository: https://github.com/seqan/sharg-parser
* GitHub Repository: https://github.com/seqan/sharg-parser
* API Documentation: https://docs.seqan.de/sharg.html
* Tutorials: https://docs.seqan.de/sharg/main_user/usergroup1.html

Expand All @@ -22,7 +22,7 @@ We have separated the feature of parsing command line arguments to its own proje

## Sharg & SeqAn

You can easily setup Sharg parallel to SeqAn as we use the exact same infrastructure.
You can easily set up Sharg parallel to SeqAn as we use the same infrastructure.

If you have completed the \ref setup, do the following to also include the Sharg parser:

Expand Down Expand Up @@ -51,4 +51,4 @@ If you have completed the \ref setup, do the following to also include the Sharg
Done!

**Now you can do the [basic tutorial of the Sharg parser](https://docs.seqan.de/sharg/main_user/tutorial_parser.html)
to learn how to conveniently access command line arguments.**
to learn how to access command line arguments conveniently.**
58 changes: 30 additions & 28 deletions doc/tutorial/03_concepts/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,16 @@ One central design goal of SeqAn is to provide generic algorithms and data struc
types without reimplementing the same algorithms over and over again for particular types.
This has multiple benefits: improved maintainability due to an additional level of abstraction
and, more importantly, the ability to reuse the code with user provided types.
A familiar example for generic code is std::vector and the algorithms in the standard library.
They are *templates* which means that they can be *instantiated* with other types.
Most often the type cannot be arbitrary, because the template expects a particular interface from the type.
A familiar example for generic code is `std::vector` and the algorithms in the standard library.
They are *templates*, which means that they can be *instantiated* with other types.
Most often the type cannot be arbitrary because the template expects a particular interface from the type.

A SeqAn example is the local alignment algorithm.
It computes the best local match between two sequences over a finite alphabet.
The algorithm is generic in so far that it allows any alphabet that offers the minimal interface which
is used inside the algorithm (e.g. objects of the alphabet type must be equality comparable).
Before C++20, this could not be checked easily and using the interface with non-conforming types would result in
very hard to read compiler errors and consequently frustration of the user.
very difficult to read compiler errors and consequently frustration of the user.
In the following part of the tutorial, you will learn how to *constrain* such template arguments of generic functions
and data structures and how this can have a huge impact on your code.

Expand Down Expand Up @@ -93,12 +93,12 @@ If you plug in a type that does not model `Addable`, you will get a message stat
template backtrace.

The standard library provides a set of [predefined concepts](https://en.cppreference.com/w/cpp/concepts).
For our example above, the std::integral concept could have been used.
For our example above, the `std::integral` concept could have been used.

## Syntax variants

Depending on the complexity of your constraint statements, three different syntaxes are available to enforce
constraints; all of the following are equivalent.
constraints; the following are equivalent.

(1) The "verbose syntax", especially useful when enforcing multiple constraints:

Expand Down Expand Up @@ -128,8 +128,8 @@ auto add(std::integral auto const v1, std::integral auto const v2) // one const
}
```

Different constraints can be applied to different template parameters and a single template parameter can be constrained
by multiple concepts.
Different constraints can be applied to different template parameters, and a single template parameter can be
constrained by multiple concepts.
Syntaxes can also be combined:
```cpp
template <std::integral t1, std::integral t2>
Expand All @@ -150,7 +150,7 @@ auto add(t1 const v1, t2 const v2)
Some people confuse concepts with *interfaces*.
Both can be used as an abstraction of concrete types, but interfaces have to be inherited from. → the abstraction
is explicit in the definition of the type.
Concepts on the other hand "describe properties from the outside". → types don't need to be related and don't need
Concepts, on the other hand, "describe properties from the outside" → types don't need to be related and don't need
to "know about the concept" to model it.

Furthermore, the polymorphism possible with concepts (see below) is faster, because it is resolved at compile-time while
Expand Down Expand Up @@ -195,79 +195,81 @@ int main()
```

The `print` function (template) should print for every object `v` passed to it the result of `to_char(v)` and it should
be constrained to only accepts types that model seqan3::alphabet.
be constrained to only accept types that model `seqan3::alphabet`.
Try calling `print` with a different type, e.g. `int` to make sure that it does.
\endassignment
\solution
\include doc/tutorial/03_concepts/overloading_solution1.cpp
\endsolution

\assignment{Assignment 2: Static polymorphism with alphabets II}
Adapt your previous solution to handle nucleotides differently from the rest. For nucleotides, it should print both the value and its complement.
Adapt your previous solution to handle nucleotides differently from the rest. For nucleotides, it should print both
the value and its complement.
\endassignment
\solution
\include doc/tutorial/03_concepts/overloading_solution2.cpp
\endsolution

## Partial template specialisation

Similar to function template overloading it is possible to use concepts for partially specialising class and variable
Similar to function template overloading, it is possible to use concepts for partially specialising class and variable
templates.

\include doc/tutorial/03_concepts/specialisation.cpp

This is a typical example of a "type transformation trait".
It maps one type to another type; in this case, it returns a type that is able to represent the square root of the
It maps one type to another type; in this case, it returns a type that can represent the square root of the
"input type".
This can be used in generic algorithms to hold data in different types depending on the type of the input –
in this case, we could avoid half of the space consumption for unsigned integral types VS signed integral types.

\note The std::same_as used above is a concept with two template parameters.
\note The `std::same_as` used above is a concept with two template parameters.
It requires that both parameters are the same. The `static_assert` checks conditions at compile-time; it can be
used to verify whether a type or a combination of types model a concept. In the above case, we can use the combination
to check the "return type" of the transformation trait.

# Concepts in SeqAn and this documentation

SeqAn uses concepts extensively, for template specialisation/overloading, to avoid misuse and improve error messages.
Unfortunately, doxygen, the system used to generate this documentation, does not handle C++ concepts very well, yet.
Unfortunately, doxygen, the system used to generate this documentation, does not handle C++ concepts very well yet.
That's why it's important to read the detailed documentation section of the constrained type, where we try to document
the requirements manually.
In some parts of the documentation concepts are called "interfaces", please don't let this confuse you.
In some parts of the documentation, concepts are called "interfaces", please don't let this confuse you.

<!-- To prevent misuse of templates and to clearly specify all public interfaces we use the concepts within
`static_assert`s in order to provoke more readable error messages. The thereby enforced requirements are also manually
documented with the respective instances. WE DO NOT ACTUALLY DO THIS... -->

## Example: seqan3::bitpacked_sequence

The class `seqan3::bitpacked_sequence<alphabet_type>` behaves just like `std::vector<alphabet_type>` but has an internal representation where multiple
values are packed into a single byte/word to save space. Also analog to `std::vector`, not every `alphabet_type` can
be used. To avoid misuse and weird error messages, the type is constrained.
The class `seqan3::bitpacked_sequence<alphabet_type>` behaves just like `std::vector<alphabet_type>` but has an
internal representation where multiple values are packed into a single byte/word to save space.
Analogously to `std::vector`, not every `alphabet_type` can be used. To avoid misuse and weird error messages,
the type is constrained.

Have a look at the documentation of [`seqan3::bitpacked_sequence`](http://docs.seqan.de/seqan3/main_user/classseqan3_1_1bitpacked__sequence.html).
It has one constrained template parameter.
Do you understand the requirements imposed on `alphabet_type` when using the
[`seqan3::bitpacked_sequence`](http://docs.seqan.de/seqan3/main_user/classseqan3_1_1bitpacked__sequence.html)?

\hint
In order to use the `seqan3::bitpacked_sequence` the `alphabet_type` must model the following:
In order to use the `seqan3::bitpacked_sequence`, the `alphabet_type` must model the following:

1. It needs to model [`std::regular`](https://en.cppreference.com/w/cpp/concepts/regular), a stl concept.
This only enforcing two other concepts: `std::semiregular<T> && std::equality_comparable<T>`.
1. It needs to model [`std::regular`](https://en.cppreference.com/w/cpp/concepts/regular), an STL concept.
This only enforces two other concepts: `std::semiregular<T> && std::equality_comparable<T>`.
* `std::semiregular<T>` makes sure that your type is default initialisable (e.g. `int i{};`).
* `std::equality_comparable<T>` makes sure you can compare your type with `==` (e.g. `i == j`).

It makes sense that in order to save a range of letters (of type `alphabet_type`), you need them to be
It makes sense that to save a range of letters (of type `alphabet_type`), you need them to be
default initialisable, for example s.t. you can easily resize your container.
Additionally, `seqan3::bitpacked_sequence` needs the `alphabet_type` to be comparable, in order be equality
Additionally, `seqan3::bitpacked_sequence` needs the `alphabet_type` to be comparable, in order to be equality
comparable itself (e.g. you can do `bit_seq_1 == bit_seq_2`).

2. It needs to model [`seqan3::writable_semialphabet`], a seqan3 concept.
This again enforces two things:
* `seqan3::assign_rank_to` needs to be defined for objects of this type.
* the type shall model `seqan3::semialphabet`,
which in summary enforces that your type is ordered (comparable via `<`), shall be efficiently copyable and
which in summary enforces that your type is ordered (comparable via `<`), shall be efficiently copyable, and
you should be able to call `seqan3::alphabet_size(c)` and `seqan3::to_rank(c)` (assuming `c` is of type `alphabet_type`).

\endhint
Expand All @@ -279,7 +281,7 @@ this concept is very SeqAn specific)?

You can learn how to make your own alphabet model the SeqAn requirements in \ref howto_write_an_alphabet

In order to understand what "make a type model a concept" means in practical terms, let's look at an easier
To understand what "make a type model a concept" means in practical terms, let's look at an easier
example in the next section.

# Satisfying a concept
Expand All @@ -294,8 +296,8 @@ Do you understand the requirements?
1. The type `T` needs to model `has_foo<T>`
Which again has two requirements:
requirement 1: The type `T` has to have a *type member* called `FOO`
requirement 2: The type `T` has to have a *member variable* calles `foo`
2. `std::same_as` is a concept that checks whether two types are exaclty the same.
requirement 2: The type `T` has to have a *member variable* called `foo`
2. `std::same_as` is a concept that checks whether two types are exactly the same.
Thus, `fooger` requires, that the *type member* `T::FOO` is `int`.
\endhint

Expand Down
Loading
Loading