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[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[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: А почему нет вызова функций с именованными аргументами?
От: 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[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[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);

а для каждого вида параметра определить свой тип.
Но такой путь коммерчески не выгоден.
И каждый день — без права на ошибку...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.