neocity/language-criticism/cpp.jade

289 lines
15 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extends ../templates/main.jade
block title
| C++ | Language Criticism | xigoi
block content
h1 C++ Language Criticism
p
| Everything that applies to
a(href="c.html") C
| also applies to C++. This article contains only things that don't apply to C.
p
| The
a(href="http://yosefk.com/c++fqa/index.html") C++ FQA
| has a lot of great points, so go read it too.
h2 Overall philosophy
p I believe that a programming language should be designed to make simple things simple and complex things as simple as possible. C++ is designed to make simple things complex and complex things even more complex. For example, a program to read space-separated numbers from STDIN, sort them and again output them space-separated:
.comparison
.compared
h6 Python 3
pre
code.
nums = [int(inp) for inp in input().split()]
print(*sorted(nums))
a(href="https://tio.run/##K6gsycjPM/7/P680t1jBViE6M69EIzOvQFMhLb9IAcgAYhBVWqKhqVdckJMJpGO5CopAyrSK84tKUlM0QFo1Nf//NzY0UTA0VbBUMDJTMFUwNgUA") Try it online!
.compared
h6 Nim
pre
code.
import std/[strutils, sequtils, algorithm]
let nums = stdin.readLine.splitWhitespace.mapIt(it.parseInt)
echo nums.sorted.mapIt($it).join(" ")
a(href="https://tio.run/##LY3LCsIwEADv@YqleGhBIrVG6MEPKHj3IB5Cs9iVvMxuvz8@6G0OM0ykUCuFnIoAizvcWcoq5HkPjO@NrH@mQrKEh1IeBeIaGC4/n6IuaN2VImrOnuS2kCBnO6MONk/SkuhsC@MUpVM4L@lfa/4O0W3OjqTTr0SxbaDpah36E/QGRjiewcBgPg") Try it online!
.compared
h6 Haskell
pre
code.
import Data.List
main = interact $ (++ "\n") . unwords . map show
. sort
. map (read :: String -> Int) . words
a(href="https://tio.run/##bcwxC8IwFATgPb/iKA6VYqDWCBZ0chHcXF0eNthg81KSJ/35sXUUbzoO7uspveww5Oz8GKLgTEL66pIo5ckxjnAsNtJDsEJZVSjuXKyh8eYpxC7NzdOI1IdJ4ScaaSb/zMujjJY6tC1uEh0/sTnhwrLIXzfnpt6hNjhgu4dBYz4") Try it online!
.compared
h6 C++
pre
code.
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> nums;
std::string inp;
while (std::getline(std::cin, inp, ' ')) {
nums.emplace_back(std::stoi(inp));
}
std::sort(nums.begin(), nums.end());
bool first = true;
for (int num : nums) {
if (first) {
first = false;
} else {
std::cout << ' ';
}
std::cout << num;
}
std::cout << std::endl;
}
a(href="https://tio.run/##ZY/NTsMwEITveYqRONSRAlIpQSINfRXkOE66wrEj24ED6rMH2/kBxM2e@WZ2V4zjfS/EPN@RFmpqJWoyzlvJh0v2o31I4Y39rXDVG0v@GrCMtMfASbMcXxngfFtVS6IO1gV6Gtx5M0I56R6kxyh9XklJsOT00ivScvkI0kWEChxwyJdipKYHOYyKC/nWcPHO1k5DLMB5Hjtv@yhjPUuRRvZxvWIt0C1b0MYYhY6s83iFt5OMYmcsWLwpwKhSZJtPHVjCNwF7uuPKpXhYADK8d2K5x0wedR2vWaHsnxcm/dl/09MnLK3O2W2eT8cnHEu84PEZJU7lNw") Try it online!
h2 Features
ul
li Despite being a very large language, C++ doesn't have basic features like sum types or pattern matching.
li Many features duplicate other features, adding their own advantages and drawbacks (and more unnecessary syntactic rules to learn). Examples: initializer lists,
code typedef
| /
code using
| ,
code #define
| /
code constexpr
| ,
code char[]
| /
code std::string
| ,
code int[]
| /
code std::array<int>
| ,
code printf
| /
code cout
| ,
code struct
| /
code class
h2 Syntax
p C++ took the horrible syntax of C and somehow managed to make it even worse.
ul
li The
a(href="https://en.wikipedia.org/wiki/Most_vexing_parse") most vexing parse
| (and similar rules). I can't fathom what could possibly cause someone to think this is a good idea.
li
a(href="https://blog.reverberate.org/2013/08/parsing-c-is-literally-undecidable.html") Parsing C++ is literally undecidable.
li Using less-than and greater-than signs as brackets, which hinders auto-pairing and complicates parsing while also looking ugly.
a(href="https://soc.me/languages/stop-using-for-generics") Here's a longer explanation from another person.
li The semicolon after a
code struct
| /
code class
| definition. Just why?
li Keywords that have multiple meanings depending on where you use them:
code static
| ,
code using
| ,
code typename
| .
li The keyword
code const
| is used to declare immutable variables (not constants, for which there is
code constexpr
| ) and it can be placed in various positions inside a type, which completely changes its meaning.
li Who decided that
code ::
| is a good path separator?
h2 Standard library
ul
li Despite being quite extensive, the standard library doesn't have basic things like
ul
li basic functions for working with strings (split, join)
li functional abstractions (map, filter, fold, …) [C++20 partially solves this with “range adaptors” (what a weird name), but the usage is unbearably cumbersome]
li optional/result types
li Using the term “vector” for a resizable array, even though the word has a completely different meaning in mathematics.
li There is no convenient way to pass a whole array/vector/list to a function, you have to do something like
code std::sort(arr.begin(), arr.end())
| .
li Weird function names: from C crypticisms (
code stoi
| ,
code fscanf
| ) to unusual words (
code emplace_back
| ).
li Idiomatically, it's required to write
code std::
| between everything from the standard library, which makes the code repetitive and unreadable. Who would have guessed that
code sort
| is a standard library function if it wasn't for the prefix?
h2 Tooling
ul
li Error messages.
ul
li If you try to search a “vector” (array) of a wrong type…
p Credit goes to
a(href="https://codegolf.stackexchange.com/a/10470/98955") this StackExchange answer
| .
pre
code.
#include <vector>
#include <algorithm>
int main() {
int a;
std::vector<std::vector<int>> v;
std::vector<std::vector<int>>::const_iterator it = std::find(v.begin(), v.end(), a);
}
a(href="https://tio.run/##jY1BDoIwEEX3PcUkbiBRDlCwVzF1OtZJoCVl7MZ49lJgoUv/6uXl/3yc54tHLOXEAceXIxgyocRk1NfY0cfE8pyMUhwEJsuhaeGtoGYTtt9xEaf1MR9@uVaMgfxHSWuMYZEbCyVbLbDA9Zg8OLgmd3fy2/kZckdVVLBtrz6lrA") Try it online!
p The error message (compiled with GCC 10.2.0) has 148 lines with about 12 kB of content, starting with:
pre
samp.
In file included from /usr/include/c++/10.2.0/bits/stl_algobase.h:71,
from /usr/include/c++/10.2.0/vector:60,
from error.cpp:1:
/usr/include/c++/10.2.0/bits/predefined_ops.h: In instantiation of bool __gnu_cxx::__ops::_Iter_equals_val<lt;_Value>::operator()(_Iterator) [with _Iterator = __gnu_cxx::__normal_iterator<lt;std::vector<lt;int>*, std::vector<lt;std::vector<lt;int> > >; _Value = const int]:
/usr/include/c++/10.2.0/bits/stl_algobase.h:1932:14: required from _RandomAccessIterator std::__find_if(_RandomAccessIterator, _RandomAccessIterator, _Predicate, std::random_access_iterator_tag) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<lt;std::vector<lt;int>*, std::vector<lt;std::vector<lt;int> > >; _Predicate = __gnu_cxx::__ops::_Iter_equals_val<lt;const int>]
/usr/include/c++/10.2.0/bits/stl_algobase.h:1977:23: required from _Iterator std::__find_if(_Iterator, _Iterator, _Predicate) [with _Iterator = __gnu_cxx::__normal_iterator<lt;std::vector<lt;int>*, std::vector<lt;std::vector<lt;int> > >; _Predicate = __gnu_cxx::__ops::_Iter_equals_val<lt;const int>]
/usr/include/c++/10.2.0/bits/stl_algo.h:3902:28: required from _IIter std::find(_IIter, _IIter, const _Tp&) [with _IIter = __gnu_cxx::__normal_iterator<lt;std::vector<lt;int>*, std::vector<lt;std::vector<lt;int> > >; _Tp = int]
error.cpp:7:87: required from here
/usr/include/c++/10.2.0/bits/predefined_ops.h:268:17: error: no match for operator== (operand types are std::vector<lt;int> and const int)
268 | { return *__it == _M_value; }
| ~~~~~~^~~~~~~~~~~
In file included from /usr/include/c++/10.2.0/bits/stl_algobase.h:67,
from /usr/include/c++/10.2.0/vector:60,
from error.cpp:1:
/usr/include/c++/10.2.0/bits/stl_iterator.h:1064:5: note: candidate: template<lt;class _IteratorL, class _IteratorR, class _Container> bool __gnu_cxx::operator==(const __gnu_cxx::__normal_iterator<lt;_IteratorL, _Container>&, const __gnu_cxx::__normal_iterator<lt;_IteratorR, _Container>&)
1064 | operator==(const __normal_iterator<lt;_IteratorL, _Container>& __lhs,
| ^~~~~~~~
/usr/include/c++/10.2.0/bits/stl_iterator.h:1064:5: note: template argument deduction/substitution failed:
li If you forget a semicolon…
p Credit goes to
a(href="https://codegolf.stackexchange.com/a/205268/98955") this StackExchange answer
| .
pre
code.
constexpr double pi = 3.0 // An engineer approximation
#include <iostream>
int main() {
std::cout << "Enter the radius: " << std::flush;
double radius;
std::cin >> radius;
std::cout << "Area: " << pi * radius * radius << std::endl;
}
a(href="https://tio.run/##ZY7NCsIwEITveYpBLypoBW9tLXjwQWKy6kK7CfkBQXz2WrXVg7dl@PabMd6vL8b0vXESE918gHX51BI8Y4/dZouiwEFAcmEhCtDeB3fjTid2otScxbTZEmp2MQXSXaMUS0KnWRZL3BUQky1L43JCXWN2lDRo0pUQtOUcS8xe@Rs6tzleq@FlHPEhqq@DBU3zl07mw1A/2ob1q5H7HVMLiW0r9ej7Jw") Try it online!
p The error message (compiled with GCC 10.2.0) has 3244 lines with about 250 kB of content, starting with:
pre
samp.
In file included from /usr/include/c++/10.2.0/iostream:38,
from error.cpp:3:
/usr/include/c++/10.2.0/x86_64-pc-linux-gnu/bits/c++config.h:258:1: error: expected , or ; before namespace
258 | namespace std
| ^~~~~~~~~
In file included from /usr/include/c++/10.2.0/iosfwd:40,
from /usr/include/c++/10.2.0/ios:38,
from /usr/include/c++/10.2.0/ostream:38,
from /usr/include/c++/10.2.0/iostream:39,
from error.cpp:3:
/usr/include/c++/10.2.0/bits/postypes.h:98:11: error: ptrdiff_t does not name a type
98 | typedef ptrdiff_t streamsize; // Signed integral type
| ^~~~~~~~~
/usr/include/c++/10.2.0/bits/postypes.h:41:1: note: ptrdiff_t is defined in header <cstddef>; did you forget to #include <cstddef>?
40 | #include <cwchar> // For mbstate_t
+++ |+#include <cstddef>
41 |
In file included from /usr/include/c++/10.2.0/bits/exception_ptr.h:40,
from /usr/include/c++/10.2.0/exception:147,
from /usr/include/c++/10.2.0/ios:39,
from /usr/include/c++/10.2.0/ostream:38,
from /usr/include/c++/10.2.0/iostream:39,
from error.cpp:3:
/usr/include/c++/10.2.0/new:126:26: error: declaration of operator new as non-function
126 | _GLIBCXX_NODISCARD void* operator new(std::size_t) _GLIBCXX_THROW (std::bad_alloc)
| ^~~~~~~~
/usr/include/c++/10.2.0/new:126:44: error: size_t is not a member of std; did you mean size_t?
126 | _GLIBCXX_NODISCARD void* operator new(std::size_t) _GLIBCXX_THROW (std::bad_alloc)
| ^~~~~~
p I guess the fourth line does tell you that you missed a semicolon (if you have the patience to scroll to it), but it's not exactly clear where.
li Would you prefer an error that I actually encountered? Here is a simplified version of some code I wrote in a programming contest:
pre
code.
#include <algorithm>
#include <iostream>
#include <numeric>
#include <string>
#include <vector>
std::string decrypt(std::string& k, std::string& m) {
std::vector<std::string> c(k.length());
int n = m.length() % k.length() == 0 ? m.length() / k.length() : m.length() / k.length() + 1;
int a = 0;
for (std::string& s : c) {
for (int i = 0; i < n; i++) {
s += a >= m.length() ? ' ' : m[a];
a++;
}
}
std::vector<int> j(k.length());
std::iota(j.begin(), j.end(), 0);
std::sort(j.begin(), j.end(), [&k](int x, int y) { return k[x] < k[y]; });
std::vector<int> q(k.length());
for (int i = 0; i < k.length(); i++) {
q[j[i]] = i;
}
std::string r = "";
for (int i = 0; i < n; i++) {
for (int ii = 0; ii < k.length(); ii++) {
char h = c[q[ii]][i];
if (c != ' ') {
r += c;
}
}
}
return r;
}
int main() {
std::string k;
std::getline(std::cin, k);
std::string m;
std::getline(std::cin, m);
std::cout << decrypt(k, m) << std::endl;
}
a(href="https://tio.run/##fZPbboMwDIbveQqv0zYQrOtuy6EPgrhgaQrhENoQplYTz87MqQldOyFE8P/F/LYDOR7fE0K67plxUjR7Cl5cJJVgMi0DQwVZVUtB40WMNyUVjOghhBhP9Mg3JbISgWHUcr/djjrsKRGXozS12CvkDizeSwt@DBhjYxZP0wMgZr4uKE9kalqWiyTjEjj4UF7D8AKKAd@HDex0@UOXtw8VGz7n/DHm3/Qvh0rA0n@NGcjoeZL7DWzYgA8POD5seyawMrB9TBgsHO/gDS/0EsaRO4GxbY/L1hhvvSf4kQCy214MBKtkbGbrL5owbloOZGvK9/1io5i6EvIuE77m0VDB2Rkqv6BxEFQ2gkMeniMsKA8vkQutSqZbOt1autcShSx6cwqzkEURcszVS56Oj0BhtXqUc9lmRczIn@8uhkLSWECKKAlPIUMTaGSeAzuASeDJ70ekdgD6wUGSmWoXo5o6JlyjNYzeRxn3jVZHe6opvzYxobJgnI6HizDuQK6Na6TLf@hS0aRqJHje9X/Le7UPDCoOukBbXfcL") Try it online!
p The error message does tell you where the error is, but you have to scroll through 228 lines with over 22 kB of content.