А почему нет вызова функций с именованными аргументами?
От: enji  
Дата: 11.09.14 09:20
Оценка: +5 -1
Тут недавно холиварчик был С vs С++, там как одно из преимуществ С была запись
struct T { int a, b; };
T t = {.a = 1, .b=42};


Если с таким разбирается компилятор С, то что мешает компилятору С++ разобраться с
void f(int a, int b);

f(.a = 1, .b=42);


Понятно, что в некоторых редких случаях в разных единицах трансляции названия аргументов f могут быть разными (или вообще отсутствовать). Но если аргументы разные и используется такой вызов, то это можно просто трактовать как нарушение ODR (очередное недиагностируемое ).

Понятно, что есть буст, но имхо, то, что там предлагается, выглядит уродливо, порождает нечитаемые сообщения об ошибках, засоряет пространство имен (или на ровном месте вводит новое), замедляет компиляцию, подозреваю также, у него есть проблемы с перегрузкой и неявными преобразованиями. Кроме того, оно требует правки хидеров или написания врапперов. Такие вещи все ж должны быть на уровне языка.

Ваше мнение?
Re[2]: А почему нет вызова функций с именованными аргументами?
От: DiZSl  
Дата: 11.09.14 10:27
Оценка: +2 -1
Здравствуйте, PM, Вы писали:

PM>Мое скромное мнение — это синтаксический оверхед Для 2-4 аргументов можно запомнить, что из них какой означает. Если аргументов больше, значит нужно менять функцию (вносить в класс, разбивать на несколько, передавать в конце концов структуру с параметрами). И да, функции Win32 API — это неизлечимая клиника.


Ну это лично ваше мнение, я считаю наоборот, что не надо использовать лишний раз структуры и классы, если для этого нет предпосылок. Win API вполне себе нормальное API (если не считать анахронизмов), а такие библиотеки как boost — вот это вот клиника.
Re: А почему нет вызова функций с именованными аргументами?
От: lithium4356  
Дата: 11.09.14 11:10
Оценка: -2
Здравствуйте, enji, Вы писали:

E>Ваше мнение?


Наше мнение — надо двигаться от усложнизма к упростизму(простигосподи), всё гениальное просто(с), вызов функции вида "f(.a = 1, .b=42)" эээ, явный перебор
Re: А почему нет вызова функций с именованными аргументами?
От: Tilir Россия http://tilir.livejournal.com
Дата: 11.09.14 11:45
Оценка: +2
Здравствуйте, enji, Вы писали:

E>Ваше мнение?


Регулярно всплывает как оформленные пропозалы

Их регулярно заворачивают взад обратно. Первым их кажется завернул лично Страуструп из C++98 proposal, так с тех пор и повелось.

В языке и без того можно найти способ
(кстати автор по моей ссылке неявно цитирует метод, также предложенный ещё Страуструпом, но мне лень искать оригинальный)

Мне кажется, это harmful, хотя бы потому, что заставляет меня иметь имена параметров как часть сигнатуры функции. Отвратительно. В сигнатуру должны входить только типы, имена должны быть up-to-me. Захотел и переименовал, не разрушив существующего кода.

Для меня более забавно, что традиционно более консервативный комитет по стандартизации C пропустил инициализацию структур в таком виде.
Re: А почему нет вызова функций с именованными аргументами?
От: uzhas Ниоткуда  
Дата: 11.09.14 11:37
Оценка: 5 (1)
Здравствуйте, enji, Вы писали:

E>Ваше мнение?


такие предложения уже были, даже либы какие-то накропали как proof of concept
https://groups.google.com/forum/#!topic/mozilla.dev.platform/2kLnr-ZPlzU
http://ehsan.github.io/namedargs/namedargs.html
http://comments.gmane.org/gmane.comp.lang.c%2B%2B.isocpp.proposals/4122
Re: А почему нет вызова функций с именованными аргументами?
От: PM  
Дата: 11.09.14 09:43
Оценка: 4 (1)
Здравствуйте, enji, Вы писали:

E>Если с таким разбирается компилятор С, то что мешает компилятору С++ разобраться с

E>
E>void f(int a, int b);

E>f(.a = 1, .b=42);
E>

...
E>Ваше мнение?

Мое скромное мнение — это синтаксический оверхед Для 2-4 аргументов можно запомнить, что из них какой означает. Если аргументов больше, значит нужно менять функцию (вносить в класс, разбивать на несколько, передавать в конце концов структуру с параметрами). И да, функции Win32 API — это неизлечимая клиника.
Re[2]: А почему нет вызова функций с именованными аргументами?
От: Caracrist https://1pwd.org/
Дата: 11.09.14 14:41
Оценка: 1 (1)
Здравствуйте, Tilir, Вы писали:


T>Мне кажется, это harmful, хотя бы потому, что заставляет меня иметь имена параметров как часть сигнатуры функции. Отвратительно. В сигнатуру должны входить только типы, имена должны быть up-to-me. Захотел и переименовал, не разрушив существующего кода.



void funct(explicit int int_param, explicit double float_param);

funct(.int_param = 5, .float_param = 0.7); // ok
funct(5, 0.5); // compile error


И пусть будет часть сигнатуры, заодно можно и расширить метаданные по функциям.
~~~~~
~lol~~
~~~ Single Password Solution
Re[2]: А почему нет вызова функций с именованными аргументами?
От: enji  
Дата: 11.09.14 10:00
Оценка: +1
Здравствуйте, Abyx, Вы писали:

A>это сломает обратную совместимость.


гм. Это каким же образом?
Re: А почему нет вызова функций с именованными аргументами?
От: DiZSl  
Дата: 11.09.14 10:22
Оценка: +1
Здравствуйте, enji, Вы писали:

E>Ваше мнение?


Мне нравиться. От себя еще добавлю, чтоб можно было вот так:

void f(int a, int b);
f(.b=42, .a = 1);
Re: А почему нет вызова функций с именованными аргументами?
От: Alexander G Украина  
Дата: 11.09.14 11:25
Оценка: +1
Здравствуйте, enji, Вы писали:

E>Ваше мнение?


Задачка Саттера "какая функция вызовется" (с шаблонными функциями, специализациями, не-шаблонными перегрузками, дефолтными параметрами) могла бы выйти на новый уровень сложности.
Русский военный корабль идёт ко дну!
Re[5]: А почему нет вызова функций с именованными аргументами?
От: Chorkov Россия  
Дата: 11.09.14 13:37
Оценка: +1
Здравствуйте, enji, Вы писали:

E>Здравствуйте, Abyx, Вы писали:


A>>ну возможно я погорячился насчет "обратной совместимости",

A>>но тем не менее твоя идея требует чтобы имена параметров были одинаковые в пределах единицы трансляции.
A>>а в тоннах легаси кода это не так.

E>Ну прям вот так уж и в тоннах? Разные имена параметров означают, что одна и таже функция определена по разному в двух разных хидерах. Насколько это частое явление?


Очень частое:
// foo.h
void foo(int a, int b);

//foo.cpp
void foo( int /* a */, int /* b */ )
{
   // а и b  не используются, поэтому, в определении их закоментировали, чтобы избежать предупреждения компилятора.
}
Re[3]: А почему нет вызова функций с именованными аргументам
От: Tilir Россия http://tilir.livejournal.com
Дата: 11.09.14 13:51
Оценка: :)
Здравствуйте, enji, Вы писали:

E>Дык и лямбды не нужны, можно же найти способ


Разумеется, лямбды не нужны.

Но в комитете по стандартизации тоже люди, лямбды позволяют писать однострочники-функторы для всяких STL-алгоритмов, писать на каждый чих классы-функторы действительно всех задолбало, и в конце концов лямбды это модно, поэтому они в стандарте. А именованные аргументы функций это скучно, никому ни для чего внятного не нужно, вызывает ассоциации с VBA и хоронит надежды на плюсовый ABI. Они и раньше-то были невелики "экспортировать класс из shared object" почти в точности означает "убить себя об стену". Но хоть для функций всё работало. Если не перегружать. И не шаблонные. И не... а черт с ними, пишем extern C.

И кроме того, Бьярни каждый раз когда ему говорят про именованные аргументы, припоминает что двадцать лет назад он эту булочку уже жевал и она ему не понравилась.

Поэтому ненужные лямбды в стандарте есть, а ненужных именованных аргументов -- нет и не будет.
Re[5]: А почему нет вызова функций с именованными аргументами?
От: enji  
Дата: 12.09.14 05:26
Оценка: +1
Здравствуйте, uzhas, Вы писали:

U>
U>//a.cpp
U>void f(int, int); // определение где-то в другом месте: в другом файле или либе

U>void g()
U>{
U>  f(4, 5);  
U>}
U>


ну и какие тут проблемы? Просто нельзя вызвать f с именоваными параметрами. Если у тебя в одной единице f(int a, int b), а в другой — f(int b, int a) — ну попытка вызвать f(.a=1, .b=2) — нарушение ODR. Такое же, как иметь две структуры с одинаковыми именами и разным содержимым.

U>еще если вспомнить про экпортированные функции, то вообще труба, еще и ABI ломать надо


Что не так с экспортированными функциями и зачем ломать abi? Данная штука ведет себя примерно так же, как и параметры по умолчанию — т.е. разворачивается компилятором в обычный вызов функции сразу в месте вызова с той информацией, которая там компилятору доступна.
Re: А почему нет вызова функций с именованными аргументами?
От: Abyx Россия  
Дата: 11.09.14 09:47
Оценка:
Здравствуйте, enji, Вы писали:

E>что мешает компилятору С++ разобраться с

E>
E>void f(int a, int b);

E>f(.a = 1, .b=42);
E>


E>Понятно, что в некоторых редких случаях в разных единицах трансляции названия аргументов f могут быть разными (или вообще отсутствовать). Но если аргументы разные и используется такой вызов, то это можно просто трактовать как нарушение ODR (очередное недиагностируемое ).


это сломает обратную совместимость.
In Zen We Trust
Re[2]: А почему нет вызова функций с именованными аргументами?
От: enji  
Дата: 11.09.14 10:09
Оценка:
Здравствуйте, PM, Вы писали:

PM>Мое скромное мнение — это синтаксический оверхед

В синтаксическом оверхеде нет ничего плохого, если он упрощает жизнь +=, ++, лямбды — все это синтаксический оверхед...

PM>Для 2-4 аргументов можно запомнить, что из них какой означает.

да как сказать. Вот к примеру я стараюсь не использовать булевых аргументов
void addElement(T, bool replace);

enum ReplaceOrNot {
  Replace, DontReplace
};
void addElement2(T, ReplaceOrNot replace);

addElement(1, false);
addElement2(1, Replace);

addElement(1, .replace=true); // также понятно, как и addElement2, но нет оверхеда с созданием enum

// да, можно сделать два метода - addElement(T), addOrReplaceElement(T) - но если булевых аргументов два - то делать четыре?
// да, можно аргументы метода передавать в виде структуры. Можно даже изобрести объект-метод addElement(1).replace(false)()
// но все это обход недостатка языка...


И опять же, пока я работаю над каким-то кодом, я помню. Но когда через год приходится в нем снова ковыряться, то я уже не помню
Re: А почему нет вызова функций с именованными аргументами?
От: NeoCode  
Дата: 11.09.14 10:38
Оценка:
Здравствуйте, enji, Вы писали:

E>Ваше мнение?


Язык C++ кривой, а его все развивают, да еще и с сохранением дурацкой "обратной совместимости". Если перечислять чего в нем нету то можно составить список из сотен пунктов.
Идея хорошая, я к ней пришел независимо и достаточно давно, но ввиду огромного количества древних костылей типа системы инклудов и прочего вряд ли это можно сделать.
Re[3]: А почему нет вызова функций с именованными аргументами?
От: Abyx Россия  
Дата: 11.09.14 11:40
Оценка:
Здравствуйте, enji, Вы писали:

E>Здравствуйте, Abyx, Вы писали:


A>>это сломает обратную совместимость.


E>гм. Это каким же образом?


ну возможно я погорячился насчет "обратной совместимости",
но тем не менее твоя идея требует чтобы имена параметров были одинаковые в пределах единицы трансляции.
а в тоннах легаси кода это не так.
In Zen We Trust
Re[2]: А почему нет вызова функций с именованными аргументами?
От: uzhas Ниоткуда  
Дата: 11.09.14 12:04
Оценка:
Здравствуйте, Tilir, Вы писали:

T>Мне кажется, это harmful, хотя бы потому, что заставляет меня иметь имена параметров как часть сигнатуры функции. Отвратительно. В сигнатуру должны входить только типы, имена должны быть up-to-me. Захотел и переименовал, не разрушив существующего кода.


соглашусь. у функций может быть много объявлений и одно определение. необходимость протаскивать одинаковые имена для параметров во всех объявлениях сильно напряжет и сломает обратную совместимость. по сути имена параметров станет частью сигнатуры. со структурами такой проблему нет: при определении структуры надо прописать один раз имена свойствам
Re[3]: А почему нет вызова функций с именованными аргументами?
От: PM  
Дата: 11.09.14 12:23
Оценка:
Здравствуйте, DiZSl, Вы писали:

DZS>Ну это лично ваше мнение, я считаю наоборот, что не надо использовать лишний раз структуры и классы, если для этого нет предпосылок. Win API вполне себе нормальное API (если не считать анахронизмов), а такие библиотеки как boost — вот это вот клиника.


Мне лень искать в WinAPI функцию кажется с 19-ю аргументами (емнип где-то в подсистеме безопасности), но вот всем известные CreateWindow и RegisterClass:
HWND WINAPI CreateWindow(
  _In_opt_  LPCTSTR lpClassName,
  _In_opt_  LPCTSTR lpWindowName,
  _In_      DWORD dwStyle,
  _In_      int x,
  _In_      int y,
  _In_      int nWidth,
  _In_      int nHeight,
  _In_opt_  HWND hWndParent,
  _In_opt_  HMENU hMenu,
  _In_opt_  HINSTANCE hInstance,
  _In_opt_  LPVOID lpParam
);


ATOM WINAPI RegisterClass(
  _In_  const WNDCLASS *lpWndClass
);

typedef struct tagWNDCLASS {
  UINT      style;
  WNDPROC   lpfnWndProc;
  int       cbClsExtra;
  int       cbWndExtra;
  HINSTANCE hInstance;
  HICON     hIcon;
  HCURSOR   hCursor;
  HBRUSH    hbrBackground;
  LPCTSTR   lpszMenuName;
  LPCTSTR   lpszClassName;
} WNDCLASS, *PWNDCLASS;


Не знаю, чем руководствовались разработчики (может быть это были 2 разных команды), но я не вижу преимуществ в способе задания параметров для CreateWindow перед RegisterClass.

Про boost в моем сообщении ничего не было, так что оставлю без комментариев.
Re[4]: А почему нет вызова функций с именованными аргументами?
От: enji  
Дата: 11.09.14 12:35
Оценка:
Здравствуйте, Abyx, Вы писали:

A>ну возможно я погорячился насчет "обратной совместимости",

A>но тем не менее твоя идея требует чтобы имена параметров были одинаковые в пределах единицы трансляции.
A>а в тоннах легаси кода это не так.

Ну прям вот так уж и в тоннах? Разные имена параметров означают, что одна и таже функция определена по разному в двух разных хидерах. Насколько это частое явление?
Да даже если в какой-то либе оно частое — просто компилятор будет ругаться при попытке вызвать ее таким образом...

Или не будет, если это разные единицы трансляции И у нас будет еще одно не диагностируемое нарушение ODR

Собственно сейчас же как то живут с таким
/// a.cpp
struct T {
  std::string s;
} a;

/// b.cpp
struct T {
  int q;
  std::string s;
} b;
Re[2]: А почему нет вызова функций с именованными аргументами?
От: enji  
Дата: 11.09.14 12:38
Оценка:
Здравствуйте, Alexander G, Вы писали:


AG>Задачка Саттера "какая функция вызовется" (с шаблонными функциями, специализациями, не-шаблонными перегрузками, дефолтными параметрами) могла бы выйти на новый уровень сложности.


ну есть такое дело. И что? Да, будут какие-то новые темные углы. И можно будет прострелить себе ногу новым способом. Но в плюсах уже есть сотни таких способов, что добавит еще один?

Для начала его можно оградить, запретив такой вызов там, где с ним вероятны проблемы...
Re[2]: А почему нет вызова функций с именованными аргументам
От: enji  
Дата: 11.09.14 12:40
Оценка:
Здравствуйте, uzhas, Вы писали:


U>такие предложения уже были, даже либы какие-то накропали как proof of concept


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

Вроде как даже было предложение в стандарт 2011 внести, но почему-то откатили

Просто счас почитал холиварчик
Автор: ramar
Дата: 04.09.14
и чет снова задумался, почему нету в плюсах, если в си добавили...
Отредактировано 11.09.2014 12:42 enji . Предыдущая версия .
Re[2]: А почему нет вызова функций с именованными аргументам
От: enji  
Дата: 11.09.14 12:45
Оценка:
Здравствуйте, Tilir, Вы писали:

T>В языке и без того можно найти способ

T>(кстати автор по моей ссылке неявно цитирует метод, также предложенный ещё Страуструпом, но мне лень искать оригинальный)

Дык и лямбды не нужны, можно же найти способ

Про описанный способ я в курсе. И если бы имелся нормальный макропроцессор (который мог бы на основе функции сделать такой класс) — он бы вполне устроил. Но сейчас это все надо писать руками или городить что-то на BOOST_PREPROCESSOR — а это сильно захламляет объявление...

T>Мне кажется, это harmful, хотя бы потому, что заставляет меня иметь имена параметров как часть сигнатуры функции. Отвратительно. В сигнатуру должны входить только типы, имена должны быть up-to-me. Захотел и переименовал, не разрушив существующего кода.


А чем функция принципиально отличается от структуры/класса в этом смысле ? Если код твой — отрефакторил, если чужой — ну что ж, придется с этим жить.

Опять же, взять тот же питон, вба, скалу (вроде бы) — там это есть, и ничего, полет нормальный...

T>Для меня более забавно, что традиционно более консервативный комитет по стандартизации C пропустил инициализацию структур в таком виде.


удобно же
Отредактировано 11.09.2014 12:53 enji . Предыдущая версия .
Re[3]: А почему нет вызова функций с именованными аргументами?
От: PM  
Дата: 11.09.14 12:47
Оценка:
Здравствуйте, enji, Вы писали:

PM>>Для 2-4 аргументов можно запомнить, что из них какой означает.

E>да как сказать. Вот к примеру я стараюсь не использовать булевых аргументов
<здесь был код>

Рекомендацию про неиспользование булевых параметров встречал только от пишущих на Java, сам проблем с ними не испытываю
Наверно дело вкуса, для меня вариант с addElement(T), addOrReplaceElement(T) вполне приемлем. Меня больше настораживает странная структура данных которая позволяет добавлять и уникальные элементы, и дубликаты.

E>И опять же, пока я работаю над каким-то кодом, я помню. Но когда через год приходится в нем снова ковыряться, то я уже не помню


Думаю тут дело не только в коде, через год придется всё равно что-то вспоминать. Вот прямо сейчас я залез в свой же код годовалой давности, вспоминаю
Re[3]: А почему нет вызова функций с именованными аргументами?
От: enji  
Дата: 11.09.14 12:49
Оценка:
Здравствуйте, uzhas, Вы писали:

U>соглашусь. у функций может быть много объявлений и одно определение. необходимость протаскивать одинаковые имена для параметров во всех объявлениях сильно напряжет и сломает обратную совместимость. по сути имена параметров станет частью сигнатуры. со структурами такой проблему нет: при определении структуры надо прописать один раз имена свойствам


Почему это у функции много объявлений? Функция объявляется в хидере, дальше хидер подключается куда надо. Если у тебя это не так — то почему тебя не напрягает требование ODR для структур?

И это второй коммент про обратную совместимость, абикс писал уже. Каким боком это нововведение ее сломает?
Re: А почему нет вызова функций с именованными аргументами?
От: -n1l-  
Дата: 11.09.14 13:01
Оценка:
Здравствуйте, enji, Вы писали:

E>Тут недавно холиварчик был С vs С++, там как одно из преимуществ С была запись

E>
E>struct T { int a, b; };
E>T t = {.a = 1, .b=42};
E>


E>Если с таким разбирается компилятор С, то что мешает компилятору С++ разобраться с

E>
E>void f(int a, int b);

E>f(.a = 1, .b=42);
E>


E>Ваше мнение?


Смешались кони, люди. Почему вы спрашиваете про именованные аргументы и в с++ приводите пример функции?
В си у вас инициализируется структура, а в с++ у вас параметризованная функция.

Например в с мы имеем здоровую структуру, а мы там частенько иемеем здоровую структуру, так что же нам делать если не все поля структуры нам нужно указать без этой фичи?
Правильно, ничего. Ничего кроме нудного указывания всех полей, подряд.
Не знаю насчет аргументов метода, но по мне в некоторых случаях читаемость улучшается. А это нынче важно, очень.
Так что мое мнение, любая фича языка, которая улучшает читабельность кода, должна присутствовать. Конечно можно сувать это куда попало, но все же полезно было бы иметь.
Re[4]: А почему нет вызова функций с именованными аргументами?
От: uzhas Ниоткуда  
Дата: 11.09.14 13:19
Оценка:
Здравствуйте, enji, Вы писали:

E>Почему это у функции много объявлений?


потому что стандарт разрешает и этим пользуются на практике
//a.cpp
void f(int, int); // определение где-то в другом месте: в другом файле или либе

void g()
{
  f(4, 5);  
}


еще если вспомнить про экпортированные функции, то вообще труба, еще и ABI ломать надо
Re: А почему нет вызова функций с именованными аргументами?
От: B0FEE664  
Дата: 11.09.14 13:22
Оценка:
Здравствуйте, enji, Вы писали:

E>Если с таким разбирается компилятор С, то что мешает компилятору С++ разобраться с

E>
E>void f(int a, int b);
E>f(.a = 1, .b=42);
E>

E>Ваше мнение?

Моё мнение такое: экономит надо не время записи, а время чтения.
Запись:
E>f(.a = 1, .b=42);
ничем не лучше, а даже хуже, чем:

const int a = 1;
const int b = 42;
f(a, b);


Но, что такое a? Что такое b? —

Вызов функции с константами определёнными по месту вызова — это экзотика для хорошего стиля.
Если в программе встречается более чем один вызов функции с одинаковыми не именованными константами, то это уже плохо. Следует либо поименовать константы, либо завернуть вызов функции в другую функцию, например:
inline void LastAnswerOnUltimateQuestion()
{
  const int nAnswerNumber = 1;
  const int nAnswerValue  = 1;
  f(nAnswerNumber, nAnswerValue);
}


Заметили ошибку? Легко исправить?
А вы бы её заметили, во всех разбросанных по коду вызовах:
// file: start.cpp
f(.nAnswerNumber = 1, .nAnswerValue = 42);
// file: background.cpp
f(.nAnswerNumber = 1, .nAnswerValue = 42);
// file: crash.cpp
f(.nAnswerNumber = 1, .nAnswerValue = 1);
?
Легко исправить?
И каждый день — без права на ошибку...
Отредактировано 11.09.2014 13:30 B0FEE664 . Предыдущая версия .
Re[2]: А почему нет вызова функций с именованными аргументами?
От: AlexRK  
Дата: 11.09.14 13:35
Оценка:
Здравствуйте, Tilir, Вы писали:

T>Отвратительно. В сигнатуру должны входить только типы, имена должны быть up-to-me. Захотел и переименовал, не разрушив существующего кода.


Кстати, а почему? Функцию ведь вы не переименуете, не разрушив существующего кода. Имя функции "более стабильно", чем имя параметра? Ой, не уверен...
Re: А почему нет вызова функций с именованными аргументами?
От: lxa http://aliakseis.livejournal.com
Дата: 11.09.14 17:29
Оценка:
Вроде, если очень припрёт, что-то похожее используя вариардики можно сделать.
Re[4]: А почему нет вызова функций с именованными аргументами?
От: lgb Канада  
Дата: 11.09.14 17:41
Оценка:
Здравствуйте, PM, Вы писали:

PM>Не знаю, чем руководствовались разработчики (может быть это были 2 разных команды), но я не вижу преимуществ в способе задания параметров для CreateWindow перед RegisterClass.


Имхо в случае использования структуры проще добавлять/убирать параметры в будущем.
Re[2]: А почему нет вызова функций с именованными аргументами?
От: Ops Россия  
Дата: 11.09.14 18:40
Оценка:
Здравствуйте, uzhas, Вы писали:

U>такие предложения уже были, даже либы какие-то накропали как proof of concept

U>https://groups.google.com/forum/#!topic/mozilla.dev.platform/2kLnr-ZPlzU
U>http://ehsan.github.io/namedargs/namedargs.html
U>http://comments.gmane.org/gmane.comp.lang.c%2B%2B.isocpp.proposals/4122

А Boost.Parameter вроде ж не только пруф?
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re: А почему нет вызова функций с именованными аргументами?
От: Кодт Россия  
Дата: 11.09.14 19:57
Оценка:
Здравствуйте, enji, Вы писали:

<>

Теоретически, можно было бы паковать аргументы в структуру
foo(FooArgs{ .a = 1, .b = 42 })


А ещё, это напоминает смолток и объектив-си, где фрагменты имени функции чередуются с аргументами
[set_a: 1 b: 42] /* void set_a:b: (int, int) - или что-то типа того */


Интересно, что перегрузка функций с одним именем и разной арностью превращается чисто в лексическую
x and y                          -- Bool.and(y)
x and: y and: z                  -- Bool.and:and:(y,z)
x and: y and: z and: t           -- Bool.and:and:and:(y,z,t)
x and: y and: z and: t and: u    -- Bool.and:and:and:(y,z,t,u)

По правде сказать, C++ная перегрузка по арности почти везде чисто лексическая (компилятор сразу считает арность и дальше смотрит только на подходяще подмножество сигнатур).
Но есть одно место, где она чуть глубже проваливается. Это когда в функцию высшего порядка передаётся имя функции, и к этому имени подбирается сигнатура согласно типу. То есть, нельзя написать foo(and) в расчёте на то, что если foo принимает трёхместную функцию, то and разрешится как and:and:and: — это совсем разные имена.

В остальном же, смолтоковский подход — это именованные аргументы для бедных. Просто в реализации, строго в компиляции, а значит, ошибкоустойчиво.
(За вычетом того, что и смолток, и объектив-си — динамические, и ошибка в имени функции может выплыть иногда только в момент вызова).
Перекуём баги на фичи!
Re[5]: А почему нет вызова функций с именованными аргументами?
От: Abyx Россия  
Дата: 11.09.14 21:05
Оценка:
Здравствуйте, enji, Вы писали:

E>Здравствуйте, Abyx, Вы писали:


A>>ну возможно я погорячился насчет "обратной совместимости",

A>>но тем не менее твоя идея требует чтобы имена параметров были одинаковые в пределах единицы трансляции.
A>>а в тоннах легаси кода это не так.

E>Ну прям вот так уж и в тоннах? Разные имена параметров означают, что одна и таже функция определена по разному в двух разных хидерах. Насколько это частое явление?


ситуаций типа
int f(int);

int f(int x) { return x + 1; }

и наоборот
inf f(int x);

int f(int) { return 42; }


— полно, причем иногда в одной единице трансляции будет несколько forward-declaration одной функции


E>Собственно сейчас же как то живут с таким

E>
E>/// a.cpp
E>struct T {
E>  std::string s;
E>} a;

E>/// b.cpp
E>struct T {
E>  int q;
E>  std::string s;
E>} b;
E>


это нарушение ODR, с этим долго не живут.
In Zen We Trust
Re[5]: А почему нет вызова функций с именованными аргументами?
От: PM  
Дата: 12.09.14 05:13
Оценка:
Здравствуйте, lgb, Вы писали:

PM>>Не знаю, чем руководствовались разработчики (может быть это были 2 разных команды), но я не вижу преимуществ в способе задания параметров для CreateWindow перед RegisterClass.


lgb>Имхо в случае использования структуры проще добавлять/убирать параметры в будущем.


В общем да, но для RegisterClass нет (см. RegisterClassEx), т.к. в структуре WNDCLASS отсутствует какая-либо информация о версии (поле с именем типа version, cbSize) и для RegisterClassEx пришлось создавать (сюрприз!) WNDCLASSEX

Наверно где-нибудь в "The Old New Thing" Raymond Chen когда-то уже рассказывал историю, почему так исторически сложилось, но на данный момент Win32 API не является образцом отличного дизайна.
Re[6]: А почему нет вызова функций с именованными аргументами?
От: enji  
Дата: 12.09.14 05:20
Оценка:
Здравствуйте, Chorkov, Вы писали:

C>Очень частое:

C>
C>// foo.h
C>void foo(int a, int b);

C>//foo.cpp
C>void foo( int /* a */, int /* b */ )
C>{
C>   // а и b  не используются, поэтому, в определении их закоментировали, чтобы избежать предупреждения компилятора.
C>}
C>


дык клиенту то виден foo.h, а не foo.cpp. А чем закончится попытка вызвать foo(.a=1, .b=2) внутри foo.cpp — вопрос. Может ошибкой компиляции, а может компилятор корректно обработает такую ситуацию — вроде как нет ничего сложного.


void foo(int a, int b);

void foo(int c, int d) {

}


foo(.a=1, .b=2); // вот тут уже однозначно ошибка компиляции
Re[2]: А почему нет вызова функций с именованными аргументами?
От: enji  
Дата: 12.09.14 05:30
Оценка:
Здравствуйте, -n1l-, Вы писали:


N>Смешались кони, люди. Почему вы спрашиваете про именованные аргументы и в с++ приводите пример функции?

N>В си у вас инициализируется структура, а в с++ у вас параметризованная функция.

потому что в с++ есть конструкторы и если разрешить именованные аргументы функций, то чуток дополненный сишный код
struct T { 
  int a, b; 
  T(int a, int b) : a(a), b(b) {}
};
T t = {.a = 1, .b=42};

будет компилироваться
Re[2]: А почему нет вызова функций с именованными аргументам
От: enji  
Дата: 12.09.14 05:36
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Моё мнение такое: экономит надо не время записи, а время чтения.

BFE>Запись:
E>>f(.a = 1, .b=42);
BFE>ничем не лучше, а даже хуже, чем:
BFE>

BFE>const int a = 1;
BFE>const int b = 42;
BFE>f(a, b);


это все мило, но кто так пишет? Это просто убивает все однострочники.
Опять же, ты можешь ошибиться и написать f(b, a). А если я напишу f(.b=42, .a=1), то это будет корректно обработано (ну по крайней мере, если применить правила из питона).
Далее, функция может иметь аргументы по умолчанию — void f(a = 1, b = 2, c = 3). И ее можно будет вызывать f(.c=4). Твой вариант с константами тут не поможет...

BFE>Но, что такое a? Что такое b? —

ну вестимо в реальной жизни аргументы не называют a и b ...

BFE>Вызов функции с константами определёнными по месту вызова — это экзотика для хорошего стиля.

BFE>Если в программе встречается более чем один вызов функции с одинаковыми не именованными константами, то это уже плохо. Следует либо поименовать константы, либо завернуть вызов функции в другую функцию, например:
BFE>
BFE>inline void LastAnswerOnUltimateQuestion()
BFE>{
BFE>  const int nAnswerNumber = 1;
BFE>  const int nAnswerValue  = 1;
BFE>  f(nAnswerNumber, nAnswerValue);
BFE>}
BFE>


Это к вопросу о нужности лямбд. Зачем нужна лямбда из одной строки, когда можно на 5 строках в другом месте файла изобразить повторно используемый функтор? Вроде как и низачем. Однако ж функторы особо не пишут, и вместо find_if фигачат цикл...
Отредактировано 12.09.2014 5:45 enji . Предыдущая версия .
Re[3]: А почему нет вызова функций с именованными аргументами?
От: enji  
Дата: 12.09.14 05:55
Оценка:
Здравствуйте, Ops, Вы писали:

Ops>А Boost.Parameter вроде ж не только пруф?


про буст я писал в исходном сообщении

BOOST_PARAMETER_NAME(graph)    // Note: no semicolon
BOOST_PARAMETER_NAME(visitor)
BOOST_PARAMETER_NAME(root_vertex)
BOOST_PARAMETER_NAME(index_map)
BOOST_PARAMETER_NAME(color_map)

BOOST_PARAMETER_FUNCTION(
      (void),                // 1. parenthesized return type
      depth_first_search,    // 2. name of the function template

      tag,                   // 3. namespace of tag types

      (required (graph, *) ) // 4. one required parameter, and

      (optional              //    four optional parameters, with defaults
        (visitor,           *, boost::dfs_visitor<>())
        (root_vertex,       *, *vertices(graph).first)
        (index_map,         *, get(boost::vertex_index,graph))
        (in_out(color_map), *,
          default_color_map(num_vertices(graph), index_map) )
      )
  )
  {
      // ... body of function goes here...
      // use graph, visitor, index_map, and color_map
  }


это ж, имхо, какой-то ужас...
Re[3]: А почему нет вызова функций с именованными аргументам
От: B0FEE664  
Дата: 12.09.14 08:51
Оценка:
Здравствуйте, enji, Вы писали:

E>Здравствуйте, B0FEE664, Вы писали:


BFE>>Моё мнение такое: экономит надо не время записи, а время чтения.

BFE>>Запись:
E>>>f(.a = 1, .b=42);
BFE>>ничем не лучше, а даже хуже, чем:
BFE>>

BFE>>const int a = 1;
BFE>>const int b = 42;
BFE>>f(a, b);


E>это все мило, но кто так пишет?

Вы сами так пишите,
Автор: enji
Дата: 11.09.14
только вместо локальных констант используете enum.

E>Это просто убивает все однострочники.

Я запись вида:
     SendAnswer(.nAnswerNumber = 1, .nAnswerPriority = 42, .nAnswerValue = 42);

буду записывать так:
     SendAnswer(
                .nAnswerNumber   = 1,
                .nAnswerPriority = 42,
                .nAnswerValue    = 42
               );

так как читать такое намного проще читать. Однострочники меня не волнуют.

E>Опять же, ты можешь ошибиться и написать f(b, a). А если я напишу f(.b=42, .a=1), то это будет корректно обработано (ну по крайней мере, если применить правила из питона).

E>Далее, функция может иметь аргументы по умолчанию — void f(a = 1, b = 2, c = 3). И ее можно будет вызывать f(.c=4). Твой вариант с константами тут не поможет...
Это хорошие аргументы до тех пор, пока мы не думаем о виртуальных методах.

E>Это к вопросу о нужности лямбд. Зачем нужна лямбда из одной строки, когда можно на 5 строках в другом месте файла изобразить повторно используемый функтор? Вроде как и низачем. Однако ж функторы особо не пишут, и вместо find_if фигачат цикл...

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

Ну и вообще, предложенный метод не достаточно радикален. Перепутать f(.a=1, .b=42) и f(.a=42, .b=1) тоже довольно просто.

Есть только один по настоящему хардкодный путь: не использовать никаких констант без user-defined суффиксов:

f(1_a, 42_b);
SendAnswer(1_answer_number, 2_answer_priority, 42_answer_value);

а для каждого вида параметра определить свой тип.
Но такой путь коммерчески не выгоден.
И каждый день — без права на ошибку...
Re[4]: А почему нет вызова функций с именованными аргументам
От: enji  
Дата: 14.09.14 16:39
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Вы сами так пишите,
Автор: enji
Дата: 11.09.14
только вместо локальных констант используете enum.

это от бедности

BFE>
BFE>     SendAnswer(
BFE>                .nAnswerNumber   = 1,
BFE>                .nAnswerPriority = 42,
BFE>                .nAnswerValue    = 42
BFE>               );
BFE>

BFE>так как читать такое намного проще читать. Однострочники меня не волнуют.

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

E>>Опять же, ты можешь ошибиться и написать f(b, a). А если я напишу f(.b=42, .a=1), то это будет корректно обработано (ну по крайней мере, если применить правила из питона).

E>>Далее, функция может иметь аргументы по умолчанию — void f(a = 1, b = 2, c = 3). И ее можно будет вызывать f(.c=4). Твой вариант с константами тут не поможет...
BFE>Это хорошие аргументы до тех пор, пока мы не думаем о виртуальных методах.
а что с ними не так? Такая штука есть например в питоне, в нем все методы виртуальные...


E>>Это к вопросу о нужности лямбд. Зачем нужна лямбда из одной строки, когда можно на 5 строках в другом месте файла изобразить повторно используемый функтор? Вроде как и низачем. Однако ж функторы особо не пишут, и вместо find_if фигачат цикл...

BFE>Потому, что для чтения кода важна локальность определения. Редко, когда один и тот же функтор используется более одного раза в программе.
Во во. Та же штука с именованными аргументами...

BFE>Ну и вообще, предложенный метод не достаточно радикален. Перепутать f(.a=1, .b=42) и f(.a=42, .b=1) тоже довольно просто.

Тут по крайней мере четко видно, что есть "а", а что есть "b"
Re[5]: А почему нет вызова функций с именованными аргументам
От: PM  
Дата: 14.09.14 18:25
Оценка:
Здравствуйте, enji, Вы писали:

E>Здравствуйте, B0FEE664, Вы писали:


BFE>>Вы сами так пишите,
Автор: enji
Дата: 11.09.14
только вместо локальных констант используете enum.

E>это от бедности

Кстати, сегодня увидел несколько иной способ использовать булевский параметры без enum:

void addElement(T, bool replace);

enum ReplaceOrNot {
  Replace, DontReplace
};
void addElement2(T, ReplaceOrNot replace);

typedef bool ReplaceOnAdd;
void addElement3(T, bool replace);

addElement3(1, ReplaceOnAdd(true));
Re[6]: А почему нет вызова функций с именованными аргументам
От: uncommon Ниоткуда  
Дата: 14.09.14 18:50
Оценка:
Здравствуйте, PM, Вы писали:

PM>Кстати, сегодня увидел несколько иной способ использовать булевский параметры без enum:


PM>
PM>typedef bool ReplaceOnAdd;
PM>void addElement3(T, bool replace);

PM>addElement3(1, ReplaceOnAdd(true));
PM>


Проблема с этим способом, как и со всеми похожими способами в С++ та, что имя параметра получается привязанным к типу (как ReplaceOnAdd к bool) и засоряет текущий namespace (нельзя в том же namespace определить новый тип ReplaceOnAdd). На самом деле, с помощью дополнительного класса и макро совсем не трудно сделать и такой синтаксис для именованных параметров:

addElement3(1, ReplaceOnAdd = true);


Но проблемы те же самые, что и у typedef bool ReplaceOnAdd.
Re[7]: А почему нет вызова функций с именованными аргументам
От: PM  
Дата: 14.09.14 20:07
Оценка:
Здравствуйте, uncommon, Вы писали:


PM>>Кстати, сегодня увидел несколько иной способ использовать булевский параметры без enum:


PM>>[ccode]

PM>>typedef bool ReplaceOnAdd;

U>Проблема с этим способом, как и со всеми похожими способами в С++ та, что имя параметра получается привязанным к типу (как ReplaceOnAdd к bool) и засоряет текущий namespace (нельзя в том же namespace определить новый тип ReplaceOnAdd).


Да, пространство имён засоряется, согласен, но не думаю что это сильно критично, ReplaceOnAdd довольно уникальное имя на мой взгляд. А так это достаточно практичный способ для тех, кто не может мириться с bool параметрами. И этот способ работает не только для bool: http://fluxible.blogspot.ru/2014/09/a-trivial-way-to-work-around-boolean.html
Re: А почему нет вызова функций с именованными аргументами?
От: sokel Россия  
Дата: 14.09.14 21:12
Оценка:
Здравствуйте, enji, Вы писали:

Да чего уж там функции, на шаблоны тоже неплохо бы продолжить. При куче default параметров сахару не хватает, до Alloc, например, минуя Compare в std::set никак не добраться.
Если извратиться, то тоже обойтись можно, взять те же packed_options в boost::intrusive, но вот как нибудь бы попроще...

C точки зрения реализации проблемы наверное те же, что с аргументами функций, можно же, переобъявляя, их переименовать сто раз.
Тогда что именем считать, first viable или может имя из имплементации? Или любое, но контролировать на совместимость?

void foo(int a, int b);
...
void foo(int b, int a) { // ой, у вас ус отклеился...
}
Re[2]: А почему нет вызова функций с именованными аргументами?
От: enji  
Дата: 15.09.14 09:41
Оценка:
Здравствуйте, sokel, Вы писали:

S>Да чего уж там функции, на шаблоны тоже неплохо бы продолжить. При куче default параметров сахару не хватает, до Alloc, например, минуя Compare в std::set никак не добраться.

+1

S>C точки зрения реализации проблемы наверное те же, что с аргументами функций, можно же, переобъявляя, их переименовать сто раз.

S>Тогда что именем считать, first viable или может имя из имплементации? Или любое, но контролировать на совместимость?

Если используется такой вызов, то можно контролировать на "одинаковость" в пределах единицы трансляции
Re[5]: А почему нет вызова функций с именованными аргументам
От: B0FEE664  
Дата: 15.09.14 10:26
Оценка:
Здравствуйте, enji, Вы писали:

E>>>Опять же, ты можешь ошибиться и написать f(b, a). А если я напишу f(.b=42, .a=1), то это будет корректно обработано (ну по крайней мере, если применить правила из питона).

E>>>Далее, функция может иметь аргументы по умолчанию — void f(a = 1, b = 2, c = 3). И ее можно будет вызывать f(.c=4). Твой вариант с константами тут не поможет...
BFE>>Это хорошие аргументы до тех пор, пока мы не думаем о виртуальных методах.
E>а что с ними не так? Такая штука есть например в питоне, в нем все методы виртуальные...

Смотрите, сейчас можно написать так:
class A
{
  public:
    virtual void f(int a) {};
};


class B : public A
{
  public:
    virtual void f(int b) {};
};


какая функция будет вызвана:
  A* p = new B;
  p->f(.a = 1);


Или вы хотите поломать совместимость кода?

BFE>>Ну и вообще, предложенный метод не достаточно радикален. Перепутать f(.a=1, .b=42) и f(.a=42, .b=1) тоже довольно просто.

E>Тут по крайней мере четко видно, что есть "а", а что есть "b"

С суффиксами это тоже видно. И стандарт менять не надо.
И каждый день — без права на ошибку...
Re[6]: А почему нет вызова функций с именованными аргументами?
От: uzhas Ниоткуда  
Дата: 15.09.14 10:55
Оценка:
Здравствуйте, enji, Вы писали:

E>ну и какие тут проблемы? Просто нельзя вызвать f с именоваными параметрами.

согласен, это согласуется с идеей ниже

E>Если у тебя в одной единице f(int a, int b), а в другой — f(int b, int a) — ну попытка вызвать f(.a=1, .b=2) — нарушение ODR. Такое же, как иметь две структуры с одинаковыми именами и разным содержимым.

это не согласуется с идеей ниже

E>Данная штука ведет себя примерно так же, как и параметры по умолчанию — т.е. разворачивается компилятором в обычный вызов функции сразу в месте вызова с той информацией, которая там компилятору доступна.

этот подход мне кажется вполне работоспособным

с другой стороны, ты выше написал про нарушение ODR, что противоречит этой идее. никакого нарушения не должно быть в примере выше, имена параметров не должны быть частью сигнатуры и проблем с экспортированными функциями опять же не будет

для случаев типа
//a.cpp
void f(int a, int b); // определение где-то в другом месте: в другом файле или либе
void f(int b, int a);

void g()
{
  f(.a = 4, .b = 5); //line (1)
}

надо просто отрубать возможность использования именованных аргументов (не компилировать такой код в строке (1) )
для дефолтных значений параметров ведь в стандарте есть несколько предложений для разруливания конфликтов, когда несколько объявлений идут в одной единице трансляции. можно что-то аналогичное прописать и для имен параметров
Re[6]: А почему нет вызова функций с именованными аргументам
От: uzhas Ниоткуда  
Дата: 15.09.14 11:04
Оценка:
Здравствуйте, B0FEE664, Вы писали:


BFE>какая функция будет вызвана:

BFE>
BFE>  A* p = new B;
  p->>f(.a = 1);
BFE>


если исходить из

Данная штука ведет себя примерно так же, как и параметры по умолчанию — т.е. разворачивается компилятором в обычный вызов функции сразу в месте вызова с той информацией, которая там компилятору доступна.

, то все очень просто : вызвается метод f из класса A, среди его аргументов ищется a. если он не найден, то компиляция ломается, если найден, то подставляется значение 1. в динамике уже вызовется метод f класса B с аргументом b=1.
Re[7]: А почему нет вызова функций с именованными аргументам
От: B0FEE664  
Дата: 15.09.14 12:06
Оценка:
Здравствуйте, uzhas, Вы писали:

BFE>>какая функция будет вызвана:

BFE>>
  A* p = new B;
  p->f(.a = 1);


U>если исходить из

U>

U>Данная штука ведет себя примерно так же, как и параметры по умолчанию — т.е. разворачивается компилятором в обычный вызов функции сразу в месте вызова с той информацией, которая там компилятору доступна.

U>, то все очень просто : вызвается метод f из класса A, среди его аргументов ищется a. если он не найден, то компиляция ломается, если найден, то подставляется значение 1. в динамике уже вызовется метод f класса B с аргументом b=1.

Т.е. такой вызов :
  B* p = new B;
  p->f(.a = 1);


"сломается"?
И каждый день — без права на ошибку...
Re[8]: А почему нет вызова функций с именованными аргументам
От: uzhas Ниоткуда  
Дата: 15.09.14 12:13
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Т.е. такой вызов :

BFE>
BFE>  B* p = new B;
  p->>f(.a = 1);
BFE>


BFE>"сломается"?


да
Re[6]: А почему нет вызова функций с именованными аргументам
От: enji  
Дата: 15.09.14 13:17
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Или вы хотите поломать совместимость кода?


совместимость кода, имхо, означает, что после некоторого нововведения имеющийся код не сломается. Так как сейчас нет именованных аргументов, то вестимо это условие выполняется. Твой случай ничем не отличается от
void f (int a);
void f (int);

void f(int b) { }

f(.b =1);


и решается точно также — компилятор ругается, если такой код встретился в рамках одной единицы трансляции. Если же разные названия в разных единицах трансляции и функция вызывается с именованными аргументами, то получается что-то вроде нарушения odr. Аналогичные нарушения для классов сейчас не диагностируются.

BFE>>>Ну и вообще, предложенный метод не достаточно радикален. Перепутать f(.a=1, .b=42) и f(.a=42, .b=1) тоже довольно просто.

E>>Тут по крайней мере четко видно, что есть "а", а что есть "b"

BFE>С суффиксами это тоже видно. И стандарт менять не надо.


а что за суффиксы?
Re[7]: А почему нет вызова функций с именованными аргументами?
От: enji  
Дата: 15.09.14 13:19
Оценка:
Здравствуйте, uzhas, Вы писали:

U>надо просто отрубать возможность использования именованных аргументов (не компилировать такой код в строке (1) )

U>для дефолтных значений параметров ведь в стандарте есть несколько предложений для разруливания конфликтов, когда несколько объявлений идут в одной единице трансляции. можно что-то аналогичное прописать и для имен параметров

дык и я про тоже — нарушение — не само объявление, а попытка вызова
Re[7]: А почему нет вызова функций с именованными аргументам
От: B0FEE664  
Дата: 15.09.14 13:38
Оценка:
Здравствуйте, enji, Вы писали:

BFE>>С суффиксами это тоже видно. И стандарт менять не надо.

E>а что за суффиксы?

Нововведение, которое позволяет записывать константы в виде 123_km, 18_precision.

2.14.8 User-defined literals

long double operator "" _w(long double);
std::string operator "" _w(const char16_t*, size_t);
unsigned operator "" _w(const char*);
int main()
{
  1.2_w; // calls operator "" _w(1.2L)
  u"one"_w; // calls operator "" _w(u"one", 3)
  12_w; // calls operator "" _w("12")
  "two"_w; // error: no applicable literal operator
}
И каждый день — без права на ошибку...
Re: А почему нет вызова функций с именованными аргументами?
От: RonWilson Россия  
Дата: 18.09.14 22:42
Оценка:
Здравствуйте, enji, Вы писали:

E>Ваше мнение?


static struct platform_device iq8134x_flash = {
    .name           = "physmap-flash",
    .id             = 0,
    .dev            = { .platform_data  = &iq8134x_flash_data, },
    .num_resources  = 1,
    .resource       = &iq8134x_flash_resource,
};


вот, к примеру, это интуитивно понятно и красиво для С инициализация структуры. Для плюсов же, в Вашем примере, не совсем понятно что Вы хотите сделать и зачем?
Отредактировано 18.09.2014 22:43 RonWilson . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.