LINUX.ORG.RU

Современно современный C++

 ,


1

4

Под современным C++ обычно подразумевают C++11. Вышедшие после него C++14 и C++17 обычно называют минорными обновлениями стандарта. И вот, с появлением C++20, а недавно и C++23 появился современно современный C++. Тавтология по аналогии с long long.

Так вот, читаю сейчас совсем свежую книгу Beginning C++23 From Beginner to Pro, седьмое издание, авторы Ivor Horton и Peter Van Weert. Книга учит программированию на C++23 и довольно неклассическим образом. Вот самая первая программа из неё:

// Ex1_01.cpp - A complete C++ program
import std;          // This line makes the entire Standard Library available,
                     // including the std::println() functionality used below

int main()
{
  int answer {42};   // Defines the variable answer with value 42
  std::println("The answer to life, the universe, and everything is {}.", answer);
  return 0;
}

Классического Hello World нет, но его написание предлагается в качестве домашнего задания и тут же намекают каков должен быть код:

exercise 1-1. Create, compile, link, and execute a program that will display the text «Hello World» on your screen.

exercise 1-2. Create and execute a program that outputs your name on one line and your age on the next line. define a variable to hold your age first.

exercise 1-3. the following program produces several compiler errors. Find and correct these errors so the program compiles cleanly.

#import std
Int main
{
  std:printn("Holla Mundo!")
)

Так же в первых главах авторы написали:

As of C++23, the preferred mechanism for outputting text to the computer’s screen is through functions such as std::println() and std::print(). We will use these in nearly every example in this book.

Короче C++23 начинает напоминать Java. Но эту тему я открыл не поэтому. Мне вот стало интересно, а как воспримут обучившегося по такой книге джуна или мидла матёрые си плюс плюснутые дядьки из реальных проектов? Вот придёт такой свежеобученный программист в реальный проект и начнёт проталкивать C++ модули везде и всюду. Что скажут старшие товарищи? Побьют или они уже и сами перешли на модули и пишут свой код так, как описано в этой книге?

Не поймите меня неправильно, в книге рассказывают и о классических стримах ввода/вывода, но даже там говорят, что std::print() и std::println() предпочтительнее:

Streams

Input and output in C++ are, as a rule, performed using streams. To output data, you write it to an output stream, and to input data, you read it from an input stream. A stream is an abstract representation of a source of data or a data sink. When your program executes, each stream is tied to a specific device that is the source of data in the case of an input stream and the destination for data in the case of an output stream. The advantage of having an abstract representation of a source or sink for data is that the programming is then the same regardless of the device the stream represents. You can read a disk file in essentially the same way as you read from the keyboard.

std::print() and std::println() are little more than thin layers on top of streams. In essence, the std::println() statement in the main() function of Ex1_01 is analogous to either one of these statements:

std::cout << std::format("The answer to life, the universe, and everything is {}.", answer) << std::endl;
std::cout << "The answer to life, the universe, and everything is " << answer << std::endl;

The standard output and input streams in C++ are called std::cout and std::cin, respectively, and by default, they correspond to your computer’s screen and keyboard. You’ll be reading input from std::cin in Chapter 2 and later chapters.

std::format() is similar to std::print(), except that instead of streaming directly to the standard output stream, std::format() returns the formatted character sequence encapsulated in a std::string object (see Chapter 7). This is why std::print() is effectively analogous to streaming the result of std::format() to std::cout, as we did in the first line of our example.

<<, finally, is the stream insertion operator that transfers data to a stream. In Chapter 2, you’ll meet the stream extraction operator, >>, which similarly reads data from a stream. Whatever appears to the right of each << is transferred to std::cout. You can insert as many strings or other values in one statement as you want (we’ll clarify how this works exactly in Chapter 13). Inserting std::endl to std::cout causes a new line to be written to the stream and the output buffer to be flushed. Flushing the output buffer ensures that the output appears immediately.

Compared to working directly with std::cout, working with std::print() and std::println() is generally both more elegant and efficient (see the next chapter for more convincing evidence). This is why we won’t use output streams that often anymore as of this edition of the book. But because output streams remain an important concept in C++ in general, we’ll briefly return to working with streams at the end of the next chapter to introduce the basic principles.

Разумеется, большинство настоящих проектов на C++ заняты вовсе не вводом/выводом в консоль. Но переход на модули наверняка меняет устоявшиеся привычки в программировании на C++ ещё во множестве других мест. Мне интересно, как это будет воспринято синьёрами помидорами? Помню как я сам начинал программировать на Java в 2006 году. Во время обучения я использовал Java 6, в которой был новый синтаксис цикла for. На собеседовании у меня был лайв кодинг и когда я начал писать такой цикл и написал двоеточие интервьюирующий меня груплид воскликнул: «это же не Pascal!» В тогдашнем проекте той конторы использовали Java 5, в которой for-each только появился.



Последнее исправление: zg (всего исправлений: 1)

Ответ на: комментарий от Bfgeshka

Потому что большое разделение крестовиков было где-то в 11 и 14.

Только в 11. После этого есть те кто принял развитие языка, и тому уже не важно 11, 14, 17, 20 или 23 - никто в здравом уме не будет держать в голове где какая фича появилась - он напишет erase_if(vector, лямбда) потому что это, блин, очевидно и правильно, и если оно не соберётся будет думать какой архаичной конструкцией его заменить. И есть те кто остановился в развитии на циклах по итераторам. Надеюсь что последних сейчас уже не осталось и индустрия не позволит им существовать, зарабатывать деньги и называть себя программистами.

anonymous
()

Сильно зависит от типа проекта. Если есть Легаси код, хочешь-нехочешь, а будь добр понять, что в нём написано и при случае исправить. Если новый проект и нет никаких зависимостей от старых инструментов, можно и 23.

seiken ★★★★★
()
Ответ на: комментарий от anonymous

Ты собирать примеры эти пробовал?

Таки да, GCC до сих пор не поддерживает P2465R3

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106852

Судя по всему в GCC 15, то есть не раньше следующего года, это начнёт работать. А вот в MSVC это уже работает.

zg
() автор топика
Ответ на: комментарий от zx_gamer

Модули — хрень. Нет систем сборки.

CMake полностью поддерживает модули.

https://www.kitware.com/import-cmake-the-experiment-is-over/

CMakeLists.txt

cmake_minimum_required(VERSION 3.28)
project(std_module_example CXX)

# Turning off extensions avoids an issue with the clang 16 compiler
# clang 17 and greater can avoid this setting
set(CMAKE_CXX_EXTENSIONS OFF)
# Set the version of C++ for the project
set(CMAKE_CXX_STANDARD 20)
# Create a library
add_library(foo)
# Add the module file to the library
target_sources(foo
  PUBLIC
    FILE_SET CXX_MODULES FILES
      foo.cxx
)
# Create an executable
add_executable(hello main.cxx)
# Link to the library foo
target_link_libraries(hello foo)

main.cxx

import foo;

int main()
{
  foo f;
  f.helloworld();
  return 0;
}

foo.cxx

// Global module fragment where #includes can happen
module;
#include <iostream>

// first thing after the Global module fragment must be a module command
export module foo;

export class foo {
public:
  foo();
  ~foo();
  void helloworld();
};

foo::foo() = default;
foo::~foo() = default;
void foo::helloworld() { std::cout << "hello world\n"; }
fsb4000 ★★★★★
()
Ответ на: комментарий от Ygor

плохо искал. есть в gcc9. в cl тоже есть с VS 2019 16.1

#include <iostream>
#include <map>
 
int main()
{
    std::map<int, char> example{{1, 'a'}, {2, 'b'}};
 
    for (int x : {2, 5})
        if (example.contains(x))
            std::cout << x << ": Found\n";
        else
            std::cout << x << ": Not found\n";
}

https://gcc.godbolt.org/z/srevqz4aq

fsb4000 ★★★★★
()
Последнее исправление: fsb4000 (всего исправлений: 1)
Ответ на: комментарий от eao197

Но как-то так вышло, что определить для своего типа operator<< для std::ostream сильно проще, чем сделать специализацию std::formatter

Да вроде плюс-минус тоже самое:

#include <print>

struct MyStruct {
    int val_;
};

template<> struct std::formatter<MyStruct>: std::formatter<std::string_view> {
    auto format(const MyStruct& msg, std::format_context& ctx) const {
        return std::format_to(ctx.out(), "MyStruct value {}", msg.val_);
    }
};


int main() {
    MyStruct st{.val_ = 15};
    std::println("{}.", st);
}

Вот если ты хочешь разбирать какое-то кастомное форматирование, то тогда придётся его действительно разбирать, но это уже за пределы operator<< выходит. А в большинстве случаев вполне достаточно отнаследоваться от реализованного.

Ivan_qrt ★★★★★
()
Ответ на: комментарий от eao197

Уж на что я люблю C#, но C# требует CLR как и Java требует JVM и из-за этого они не годятся на полную замену C++. Хотя ИМХО кучу софта на C++ можно безболезненно было бы делать на C#. Rust это внезапно замена сишки, а не C++ и сомнительная, в том плане что всё на фундаментальном уровне завязано на сишку и отвязываться от этого очень долго (вплоть до того что библиотеки с разных ЯП цепляются через сишные обёртки, словно это сишные библиотеки). Реально, заменой C++ пытался стать только язык D, но он почему-то не смог раскрутиться, хотя современный C++ всё более похож на него делается.

anonymous
()
Ответ на: комментарий от Ygor

А ну тебе с js компилятором виднее.

Ясно понятно.

Дурачок вместо благодарностей и того что он забыл добавить флаг, который задаёт стандарт при сборке начинает съезжать на то что godbolt.org это левый сайт.

Дурачок не понимает что в сообществе C++ это очень известный сайт.

Наверняка такой бездарь, как ты, ещё и каким-нибудь «ведущим разработчиком» работает или «главой разработки».

Когда же навернётся необоснованный хайп в it и все пицценосцы уйдут разносить пиццу? Надеюсь Chat GPT и Copilot приближают этот день.

fsb4000 ★★★★★
()
Ответ на: комментарий от zg

Не всё, т.к. в линуксах у C# GUI только недавно завезли какой-то в виде авалонии, а дофига опенсорс проектов, которые не хотели завязываться на оффтопик онли из-за этого вынужденно выбирали C++ как язык для разработки. Можно сказать что у Java есть GUI, но он традиционно марсианский и долгий старт JVM в сравнении с CLR (в случае когда софтина уже работает это не так важно, потому всякому серверному софту срать на это, будет стартовать программа 0,1 секунды или 3 секунды, там важно как быстро она будет работать, а вот у десктоп юзера попа сгорает когда калькулятор открывается пару секунд) отнимают массу пользователей, я вот только 2 java программы на десктопе знаю не считая совсем специфичных типа IDE или серверного ПО - это майнкрафт и jdownloader.

anonymous
()

Интересное наблюдение на https://en.cppreference.com/w/cpp/compiler_support/23 - GCC лидирует по реализованным языковым фичам современного C++ (первая таблица), при этом MSVC лидирует по реализованным фичам стандартной библиотеки современного C++ (вторая таблица). В частности Standard Library Modules P2465R3 в MSVC уже реализовано и именно поэтому пример кода из книге о C++23 там собирается и работает, а в GCC 14.1 (и даже в GCC trunk) это не поддерживается и поэтому не собирается со следующей ошибкой:

In module imported at <source>:1:1:
std: error: failed to read compiled module: No such file or directory
std: note: compiled module file is 'gcm.cache/std.gcm'
std: note: imports must be built before being imported
std: fatal error: returning to the gate for a mechanical issue
compilation terminated.
Compiler returned: 1

Флаги компиляции -std=c++23 -fmodules-ts

Ещё один сайт о состоянии поддержки современного C++ в стандартной библиотеки GCC https://gcc.gnu.org/wiki/LibstdcxxTodo

zg
() автор топика
Последнее исправление: zg (всего исправлений: 3)
Ответ на: комментарий от fsb4000

Дурачок вместо благодарностей и того что он забыл добавить флаг, который задаёт стандарт при сборке начинает съезжать на то что godbolt.org это левый сайт.

Да действительно забыл флаг. Вернее думал что оно по умолчанию там есть.

Надеюсь Chat GPT и Copilot приближают этот день.

Удачи «умненькому» мальчику в опровержении теорем Гёделя

Ygor ★★★★★
()
Ответ на: комментарий от Ivan_qrt

Я вот попробовал набросать простенький пример: https://wandbox.org/permlink/xSpTj4PNJ05rQvEK Ничего сложного, все делается с полпинка.

Попробовал переделать его под std::formatter. И уперся в то, что не понимаю, как разобраться с френдами :(

Может вы знаете?

Остановился вот на этой попытке: https://wandbox.org/permlink/zc8ZQoprfrIfHf3g

Ну и замечу два важных отличия при переходе на std::formatter:

  1. Специализацию std::formatter нужно делать в пространстве имен std. Т.е., если я в проекте определяю свой тип в своем пространстве имен, то мне нужно прервать свое пространство имен, открыть пространство std, определить там специализацию std::formatter, закрыть пространство std, открыть свое пространство имен.

  2. Т.е. в специализации std::formatter тип возвращаемого значения для format – это auto, то у меня так просто не получится задекларировать этот самый format в заголовочном файле, а реализовать в .cpp-файле. Возможно, когда-нибудь, когда большая часть проектов переедет на модули, это перестанет играть хоть какую-то роль. Но пока что модули доступны не только лишь всем (как и C++20, не говоря уже про C++23).

eao197 ★★★★★
()
Ответ на: комментарий от eao197

https://wandbox.org/permlink/zwKVpF2dUtdUFLHZ

  1. Да, это правда, и это не приятно. Но на мой вкус плюсы пока перевешивают.

  2. Отдельную декларацию я не проверял и м.б. плохо понял проблему. Но если виноват auto, его вполне можно заменить на std::format_context::iterator. format должен возвращать ctx.out() смещённый на занятое кол-во позиций.

Ivan_qrt ★★★★★
()
Ответ на: комментарий от eao197

Можно ещё так сделать, так удобнее и частично решает первую проблему.

Но френдить доступ к внутреннему классу из std::formatter всё равно приходится.

Ну и любой может сравнить количество телодвижений для реализации operator<< и специализации std::formatter

Разница появляется только в сложных случаях и она не значительна. Впрочем тут каждый для себя решает, это да.

Ivan_qrt ★★★★★
()
Ответ на: комментарий от zx_gamer

В смысле?

В прямом.

Напишите вывод на stdout размер контейнера, например. Ну типа есть std::vector<int>, нужно напечатать его размер.

Вопрос использования printf-ов в шаблонах даже поднимать не будем.

eao197 ★★★★★
()
Ответ на: комментарий от anonymous

никто в здравом уме не будет держать в голове где какая фича появилась

Ок, «младоинтервьюэры» и старперы точно не в здравом уме. У первых еще своего еще нету и они думают заучивание «бестпрактисов» (ТМ), т.е. новых блестящих костылей С++ для подпирания предыдущих повод гордиться (что место в мозгу не бесконечно они поймут потом), а вторые застряли в «нормальном-то сиплюсплюсе 90-х» (выучили 100500 старых сломаных костылей и гордятся… тем чего на самом деле не помнят, т.к. их мозги уже не те).

anonymous
()
Ответ на: комментарий от zurg

плюсы сами себя хорошо закапывают

не прошло и… сколько даже не лет а стандартов

У них хотя бы стандарты есть. В отличие от модных и молодежных «других-то языков», фанаты которых слышать ничего не хотят про реальный мир за пределами уютной эхо-камеры, пока свет не мигнет. И да, пока стандартов у «других-то языков»(ТМ) нет, слухи о закапывании чего-либо со стандартами – просто слухи. Оно еще на похоронах очередных закапывателей простудится.

anonymous
()

Любой другой язык программирования порождает срачи типа «Говно ваш ЯП1, толи дело ЯП2». И только С++ знаменит тем, что в нём всегда одни плюсовики яростно пидорят других плюсовиков чей С++ монее ортодоксальный. Собственно, этого одного наблюдения достаточно, чтобы никогда не связываться с С++ и не пытаться его понять ибо его не понимает никто, а те кто понимает им не пользуются

FishHook
()
Ответ на: комментарий от zx_gamer

Зачем int?

Внимательный вы мой, вы что, очередной LOR-овский шизофреник? Здесь вижу, здесь не вижу, здесь голоса в своей голове озвучиваю?

Вот код:

std::vector<int> v;
fill_values(v);
std::cout << v.size() << std::endl; // (1)

Замените строчку (1) на printf/fprintf или что там вашим голосам роднее.

Сможете?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Замените строчку (1) на printf/fprintf или что там … Сможете?

Смогу: там гарантированный size_t и %zu прекрасно отработает :) Гугл подсказывает что можно нарваться на грабли с MSVC до 15-го, но «проблемы индейцев шерифа мало волнуют», и вообще - мы же вроде всё самое «последнее / модное / молодёжное» обсуждаем. Но идея предельно понятна - надо было неопределённость по типу оставлять, и тогда точно «здравствуйте девочки, здравствуйте мальчики» (overloads and/or traits).

bugfixer ★★★★★
()
Ответ на: комментарий от dvetutnev

я подзадолбался. std::println(«var1: {}, var2: {}», var1, var2); всяко проще, и читать тоже проще.

принт с форматной строкой сложней, поскольку требует разбора строки и прочих ненужностей внутри вызова принта.

то-ли дело в поток «покидал»(строго говоря просто вызвал конкретные функции принта безо всяких там разборов формата) в нужном порядке.

alysnix ★★★
()

Мне вот стало интересно, а как воспримут обучившегося по такой книге джуна или мидла матёрые си плюс плюснутые дядьки из реальных проектов? Вот придёт такой свежеобученный программист в реальный проект и начнёт проталкивать C++ модули везде и всюду. Что скажут старшие товарищи?

попросят обосновать применение модулей с цифрами и фактами. Еще посоветуют не читать книги, в которых пишут «return 0» в конце main

Lrrr ★★★★★
()
Ответ на: комментарий от zx_gamer

Зачем int? Нет никакого смысла использовать примитивы, когда можно сделать нормальные классы, которые будут работать так же быстро и занимать так же мало места.

Классы никогда работать так же быстро, как примитивы, не будут.

zg
() автор топика
Ответ на: комментарий от Bfgeshka

Если кодобазу будет муторно переводить на модули, то просто не станут и всё тут.

Не надо ничего переводить, модуль это следующий уровень над инклудами - интерфейс всей либы целиком надо обернуть в один модуль, а внутри там спокойно могут быть include, и это норм, никакой не «устаревший стиль»

kvpfs_2
()
Ответ на: комментарий от Ivan_qrt

На godbolt.org и в транке ещё нет, то есть import std; там приводит к ошибке компиляции. И баг на эту тему всё ещё не пофиксен. Возможно ты имеешь в виду #include <print> который так же позволяет использовать std::print() std::println(). Но даже это кое где глючит:

$ cat 1.cpp
#include <print>

int main()
{
    std::println("Hello there...");
}

$ g++ --version
g++.exe (Rev3, Built by MSYS2 project) 14.1.0
Copyright (C) 2024 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ g++ -std=c++23 1.cpp
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/14.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\msys64\tmp\ccurfqxs.o:1.cpp:(.text$
_ZSt14vprint_unicodeP6_iobufSt17basic_string_viewIcSt11char_traitsIcEESt17basic_format_argsISt20basic_format_contextINSt8__format10_Sink_ite
rIcEEcEE[_ZSt14vprint_unicodeP6_iobufSt17basic_string_viewIcSt11char_traitsIcEESt17basic_format_argsISt20basic_format_contextINSt8__format10
_Sink_iterIcEEcEE]+0x197): undefined reference to `std::__open_terminal(_iobuf*)'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/14.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\msys64\tmp\ccurfqxs.o:1.cpp:(.text$
_ZSt14vprint_unicodeP6_iobufSt17basic_string_viewIcSt11char_traitsIcEESt17basic_format_argsISt20basic_format_contextINSt8__format10_Sink_ite
rIcEEcEE[_ZSt14vprint_unicodeP6_iobufSt17basic_string_viewIcSt11char_traitsIcEESt17basic_format_argsISt20basic_format_contextINSt8__format10
_Sink_iterIcEEcEE]+0x24d): undefined reference to `std::__write_to_terminal(void*, std::span<char, 18446744073709551615ull>)'
collect2.exe: error: ld returned 1 exit status

Хотя было заявлено об этом, как о поддерживаемой фиче 14-го GCC.

zg
() автор топика
Ответ на: комментарий от Ivan_qrt

Почему? Какая разница в производительности будет между struct { int val; } и int?

Я по аналогии с Java так подумал. А что, в C++ что int, что struct { int val; } - одно и то же в ассемблере?

zg
() автор топика
Ответ на: комментарий от zg

Есть странные ритуалы, я особенно ненавижу украшательство в комментариях когда делают:

/*~+~+~+~+~++~+~+~+~++~+~++~+~+~+~+~++~+~+~~*/
/*******[ HELLO WORLD FUNCTION ]*************/
//////////////////////////////////////////////
///                                         //
/// PRINT                                   //
/// HELLO                                   //
/// WORLD                                   //
///                                         //
//////////////////////////////////////////////
void hello_world();

MOPKOBKA ★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 2)
Ответ на: комментарий от zg

А что, в C++ что int, что struct { int val; } - одно и то же в ассемблере?

оптимизировать работу со структурами, исходя из их размера и смешений полей - это намана для любого языка, где они есть. хоть для паскаля, хоть си, хоть ады, хоть хрензнаетчего. этим озабочиваются разрабы компиляторов, работа у них такая.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от zg

про монализу со случайными последовательными мутациями за миллион поколений вы в каменоломнях древних анннунаков чёто херню городите.

ошиблись на много порядков.

вот смотри, вот на БуКа-шке гораздо быстрее монализа получаеццо:

manwe…zx_vs_bk

Мона Лиза - алгоритм построения портрета в 256 байт. Слева программа для ZX Spectrum 3.5 МГц, справа программа для БК 0010 3 МГц. Запись экрана с эмуляторов Fuse и Gid соотвтетсвенно. Скорость эмуляции 100% как у оригинальных компьютеров.

Видно, что БК заканчивает построение чуть быстрей. При этом БК отрисовывает полную картинку (96 линий), а ZX Spectrum пропускает нижние линии (рисует только 88). Градации серого на ZX Spectrum сделаны смешением чёрных и белых точек, а на БК использованы полноценные 4 оттенка (правда, такой монохромный режим присутствовал лишь на ранних моделях БК 0010, а пользователям более поздних моделей приходится паять шнур-переходник с цветного видеовыхода на монохромный). Программа на ZX Spectrum состоит из 79 инструкций, программа на БК - из 42 инструкций. Конечно, обе программы можно ускорить, но ценой выхода за ограничение размера 256 байт.

Читайте внимательно. Не случайных. Последовательных. Ну, да по времени может соврал на 10^64 порядков… Хотя конечно всё зависит от разрешения изображения.

да он на дохрена порядков соврал.

вот они, утерянные технологии древних предков. с полигональной кладкою.

на стародревней букашечке немного быстрее спектрума получается.

вообще у него в тестах было сравнение, не такая уж букашечка и медленная (смотря с чем сравнивать, конечно же).

anonymous
()
Ответ на: комментарий от zg

Изучая окаменелости мы можем судить какими была фауна и флора. И самое удивительное, что некоторые представители практически не поменялись за десятки и сотни тысячь лет (и даже милионы), а некоторые поменялись. Что это доказывает? А ничего. Нет какой-то системы почему одни менялись, а другие нет.

ещё один. система есть – только вы её не понимаете.

в упор смотрите – а не видите. потому что смотрите не туда и думаете не о том.

потому что она 1) открытая 2) сложная 3) эволюционирующая, с хаотической динамикой и синергетикой на границе хаоса и порядка 4) развивающаяся нелинейно 5) эволюционирующая неравномерно 6) цели нет, но есть путь.

Если всё «промыслительно», то тот кто всё сотворил скорее запустил мехханизм, который всё и построил/настроил.

этот механизм и есть эта система. и метасистема. и метасистемный переход.

anonymous
()