// indexof.cpp
#include <cstdlib>
#include <iostream>
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cerr << "missing argument/n";
std::exit(1);
}
int j = 1;
while (++j < argc) {
if (std::strcmp(argv[1], argv[j]) == 0)
break;
}
if (j != argc) {
std::cout << j - 2;
}
}
$ indexof
missing argument
$ indexof C A B C D
2
$ indexof X A B C D
$
Can we make it better?
First, error if there’s less than 1 arg
At while
, “let’s see if we can figure this out”
In summary, 3 parts:
One of these parts required some thinking. What can we do to make this code better?
indexof.cpp
// indexof.cpp
#include <cstdlib>
#include <iostream>
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cerr << "missing argument/n";
std::exit(1);
}
int j = 1;
while (++j < argc) {
if (std::strcmp(argv[1], argv[j]) == 0)
break;
}
if (j != argc) {
std::cout << j - 2;
}
}
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
$ indexof
missing argument
$ indexof C A B C D
2
$ indexof X A B C D
$
Dolor sed viverra ipsum nunc aliquet bibendum. Tortor at risus viverra adipiscing at in.
// indexof.cpp
#include <cstdlib>
#include <iostream>
int search(int argc, char* argv[]) {
int j = 1;
while (++j < argc) {
if (std::strcmp(argv[1], argv[j]) == 0)
break;
}
return j;
}
int main(int argc, char* argv[]) {
if (argc < 2) { std::exit(1); }
const int j = search(argc, argv);
if (j != argc) { std::cout << j; }
}
OK, “algorithm” is a ridiculous name for an algorithm. Just like “string” is a ridiculous name for a string.
// indexof.cpp
#include <cstdlib>
#include <iostream>
int find(int argc, char* argv[]) {
int j = 1;
while (++j < argc) {
if (std::strcmp(argv[1], argv[j]) == 0)
break;
}
return j;
}
int main(int argc, char* argv[]) {
if (argc < 2) { std::exit(1); }
const int j = find(argc, argv);
if (j != argc) { std::cout << j; }
}
find
as vocabulary function, enabling reuse.find
, so let’s look at it on its own.
int find(int argc, char* argv[]) {
int j = 1;
while (++j < argc) {
if (std::strcmp(argv[1], argv[j]) == 0)
break;
}
return j;
}
How can you tell?
/// Returns the least `j` such that j > 1 && j < argc
/// && std::strcmp(argv[1], argv[j]) == 0`, or `argc` if no such `j` exists.
int find(int argc, char* argv[]) {
int j = 1;
while (++j < argc) {
if (std::strcmp(argv[1], argv[j]) == 0)
break;
}
return j;
}
✅ Summary paragraph is a sentence fragment.
✅ Document non-mutating functions in terms of what they return.
a condition or predicate that must always be true just prior to the execution of some section of code or before an operation in a formal specification.
—Wikipedia (wikipedia.org/wiki/Precondition)
/// Returns the least `j` such that `j > 1 && j < argc
/// && std::strcmp(argv[1], argv[j]) == 0`, or `argc` if no such `j` exists.
///
/// - Requires: `argv[j]` is a C string where `j >= 1 && j < argc`.
int find(int argc, char* argv[]) {
int j = 1;
while (++j < argc) {
if (std::strcmp(argv[1], argv[j]) == 0)
break;
}
return j;
}
Sean notes Hoare logic is bottom-up and propagates complexity. DBC is top-down and minimizes it.
Red flag: documentation reads like implementation.
/// Returns the first index of `argv`'s 2nd element in the remainder of `argv`,
/// or `argc` if it can't be found.
///
/// - Requires: `argv[j]` is a C string where `j >= 1 && j < argc`.
int find(int argc, char* argv[]) {
int j = 1;
while (++j < argc) {
if (std::strcmp(argv[1], argv[j]) == 0)
break;
}
return j;
}
argv[1]
” by itself means find the same pointer value.argv
is interpreted as an array of C-strings.argv
has length argc
./// Returns the first index of `argv`'s 2nd element in the remainder of `argv`,
/// or `argc` if it can't be found.
///
/// - Requires: `argv` is an array of `argc` C-strings.
int find(int argc, char* argv[]) {
int j = 1;
while (++j < argc) {
if (std::strcmp(argv[1], argv[j]) == 0)
break;
}
return j;
}
⮕ In raising abstraction of the precondition, we also tightened it
⮕ Now we can use the summary to think about
👉🏿 Precondition is tightened
argv[0]
is now a C-stringargc
> 1/// Returns the first index of `argv`'s 2nd element in the remainder of `argv`,
/// or `argc` if it can't be found.
///
/// - Requires: `argv` is an array of `argc` C-strings.
int find(int argc, char* argv[]) {
int j = 1;
while (++j < argc) {
if (std::strcmp(argv[1], argv[j]) == 0)
break;
}
return j;
}