А зачем?
В сложных случаях, да, оно полезнее. В простых — нет.
В некоторых языках (Python) можно и так, и так.
Но что Вы будете делать, если в следующей версии библиотеки кто-то переименует параметры в заголовочном файле, считая, что 99.9% вызывающих делают это позиционными параметрами, а кто не сделал так — тот ССЗБ?
Здравствуйте, netch80, Вы писали:
N>А зачем?
Дабы облегчить чтение кода.
N>В сложных случаях, да, оно полезнее. В простых — нет.
Полезно во всех ситуациях.
Не так давно правил багу, которую внесли при рефакторинге.
Здравствуйте, netch80, Вы писали:
N>А зачем? N>В сложных случаях, да, оно полезнее. В простых — нет. N>В некоторых языках (Python) можно и так, и так.
Для профилактики ошибок прежде всего. Например чтобы не перепутать порядок одинаково типизированных параметров при вызове. Да я в курсе, что современные IDE очень этому препятствуют, и такого типы ошибок редко встречаемы, но лишним оно, имхо, не было бы.
N>Но что Вы будете делать, если в следующей версии библиотеки кто-то переименует параметры в заголовочном файле, считая, что 99.9% вызывающих делают это позиционными параметрами, а кто не сделал так — тот ССЗБ?
Изменять вызовы буду. Опять если для такого языка будет существовать развитая IDE, то это будет происходить очень быстро и в полуавтоматическом режиме.
Контрпример: есть у нас функция API —
DrawRectangle(int top, int left, int length, int width);
В следующей версии API ее поменяли на
DrawRectangle(int left, int top, int length, int width);
И пофигу в каком там порядке идут параметры в объявлении функции.
А вот читабельности такой подход, ИМХО, не прибавляет совершенно, только добавляя визуальный мусор.
А насколько описанная мною проблема надумана, я не знаю. Я за то, чтобы было как в питоне: хочешь указывать — указывай, не хочешь — не указывай.
Здравствуйте, Философ, Вы писали:
Ф>Здравствуйте, netch80, Вы писали:
N>>А зачем? Ф>Дабы облегчить чтение кода.
Мне кажется оно только затрудняет чтение визуальным шумом, сильно лучше не использовать магических чисел/строк/булевых значений, и не использовать одну переменную для разных задач.
N>>В сложных случаях, да, оно полезнее. В простых — нет. Ф>Полезно во всех ситуациях. Ф>Не так давно правил багу, которую внесли при рефакторинге.
Ф>Вызов выглядел так: Ф>GetParameters(c_QueryReportName);
Ф>А сам метод выглядел вот так: DbParameter[] GetParameters(string QueryText)
Разъясните пожалуйста что здесь не так-то было? Чем вам помогло бы, если бы было —
GetParameters( QueryText = c_QueryReportName);
Кстати, а почему вызов эти самые параметры никуда не возвращает? N>>Но что Вы будете делать, если в следующей версии библиотеки кто-то переименует параметры в заголовочном файле...
Ф>Это будет свинство чистой воды. Однако нажму Ctrl+H и заменю код вызовов (с ребилдом и тестированием — максимум час).
Нормальный рабочий момент, если конечно речь не идет о вызове API OS или чего-то подобного. А если вызов внутренний, то рефакторинг может такое вполне породить из-за неудачного имени параметра например, но я думаю это достаточно просто автоматизируется в статически типизированных языках.
Собствеенно, такое уже реализовано в некоторых языках. В том же C#, например. Только значение указывается через двоеточие, а не знак равно:
CreateTimer(interval: 100, repeats: false);
Указывать параметры в таком виде можно в любом порядке. При изменении названия параметра в определении метода, IDE меняет название в вызове метода. Проблем не возникает при рефакторинге.
Насчёт визуального шума. Думаю, такую запись стоит применять лишь в том случае, когда в методе много параметров одного типа, чтобы ненароком не ошибиться.
Причем ни переставлять, ни пропускать аргументы нельзя, т.к. withObject и waitUntilDone — не имена параметров, а части имени метода. (Т.е. метод называется не performSelectorOnMainThread, а performSelectorOnMainThread:withObject:waitUntilDone: )
Вот вот, согласен. А то "наезды" на бул ради бредовой красоты в явовском стиле (увеличивающем размер кода раза так в 3) раздражают. А вот питоновский стиль — это совсем другое дело... Удобно и красиво одновременно. Правда в единственном современном системном языке такого к сожалению ждать не приходится. А жаль.
Здравствуйте, v2kochetov, Вы писали:
V>Здравствуйте, Философ, Вы писали:
Ф>>Здравствуйте, netch80, Вы писали:
N>>>А зачем? Ф>>Дабы облегчить чтение кода. V>Мне кажется оно только затрудняет чтение визуальным шумом
не согласен, не так уж много шума это добавляет.
Ф>>Вызов выглядел так: Ф>>GetParameters(c_QueryReportName);
V>Разъясните пожалуйста что здесь не так-то было? Чем вам помогло бы, если бы было - V>
24>Причем ни переставлять, ни пропускать аргументы нельзя, т.к. withObject и waitUntilDone — не имена параметров, а части имени метода. (Т.е. метод называется не performSelectorOnMainThread, а performSelectorOnMainThread:withObject:waitUntilDone: )
О, привет Алану Кею. Это ж Старшая Речь!
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Философ, Вы писали:
Ф>Здравствуйте, netch80, Вы писали:
N>>А зачем? Ф>Дабы облегчить чтение кода.
Мне оно не облегчает, а усложняет, по крайней мере в пределах первых до 5 позиционных параметров. (Точная граница сильно приблизительна.)
Есть функции, которые знаешь наизусть и вызываешь единообразно независимо от места определения. Например, если говорить о системных и около того, то это open(), exit(), stat(), socket(), bind() и так далее. Вводить ещё какие-то имена параметров к ним... лучше в сад.
А вот если у функции может быть 1-2 обязательных параметра и дофига специальных на отдельный случай — вот тогда вводить имена для них — самое оно. И такие варианты стиля есть. Я не против видеть такое, например, в C++, но только в порядке "дополнительных" возможностей для параметров со значениями по умолчанию.
N>>В сложных случаях, да, оно полезнее. В простых — нет. Ф>Полезно во всех ситуациях. Ф>Не так давно правил багу, которую внесли при рефакторинге.
Ф>Вызов выглядел так: Ф>GetParameters(c_QueryReportName);
Ф>А сам метод выглядел вот так: DbParameter[] GetParameters(string QueryText)
Честно говоря, нифига в этом примере не понял. c_ которое чего-то там Name это разве не строка? Почему нельзя передать его туда, где ожидается текст?
Или вопрос в том, что требовался текст запроса, а Вы передали его имя?
Прошу приводить пример так, чтобы не надо было гадать на кофейной гуще для его расшифровки.
С другой стороны, я могу привести в пример ещё кучу API, в котором возможно, например, перепутать параметры местами. И что?
И должен заметить, что рефакторинг вообще-то положено делать, предварительно обложив код тестами со всех сторон. И если баги подобного рода вносятся при рефакторинге, это значит, что для данного рефакторинга не были соблюдены входные условия. Более того, если следовать самому строгому определению, это вообще не рефакторинг, а какая-то ручная доработка.
N>>Но что Вы будете делать, если в следующей версии библиотеки кто-то переименует параметры в заголовочном файле... Ф>Это будет свинство чистой воды. Однако нажму Ctrl+H и заменю код вызовов (с ребилдом и тестированием — максимум час).
Хорошо, приведу другой пример — ближе к моей практике. Стандартизация Posix определяет у функций набор параметров с их позициями. Имена не задаются. Если я возьму имя, которое вписано на NetBSD, а компиляция сорвётся на Linux, что мне делать? Или в языке в таком случае имя должно было быть фиксировано в определении интерфейса?
Я не отрицаю Ваши соображения полностью. Более того, я сам периодически использую такой стиль там, где это важно. Есть языки, которые позволяют такое (в первую очередь имею в виду Python, у него правила соответствия вызова определению функции тут достаточно гибки и при этом однозначны, чтобы не получить неожиданные эффекты). Но я бы не стал устанавливать это обязательным для всех случаев: вот это точно задолбёт.
Здравствуйте, v2kochetov, Вы писали:
N>>А зачем? N>>В сложных случаях, да, оно полезнее. В простых — нет. N>>В некоторых языках (Python) можно и так, и так. V>Для профилактики ошибок прежде всего. Например чтобы не перепутать порядок одинаково типизированных параметров при вызове. Да я в курсе, что современные IDE очень этому препятствуют, и такого типы ошибок редко встречаемы, но лишним оно, имхо, не было бы.
Мнэээ... вопрос: какая доля подобных ошибок среди реально встречающихся на практике? Причём таких, которые не ловятся минимально проработанным набором тестов кода или крайне трудно уловимы при ручном (глазами) ревью кода?
N>>Но что Вы будете делать, если в следующей версии библиотеки кто-то переименует параметры в заголовочном файле, считая, что 99.9% вызывающих делают это позиционными параметрами, а кто не сделал так — тот ССЗБ? V>Изменять вызовы буду. Опять если для такого языка будет существовать развитая IDE, то это будет происходить очень быстро и в полуавтоматическом режиме. V>Контрпример: есть у нас функция API — V>
V>DrawRectangle(int top, int left, int length, int width);
V>
V>В следующей версии API ее поменяли на V>DrawRectangle(int left, int top, int length, int width);
Вообще-то здесь основная проблема будет в подобном преобразовании API: за подобное надо бить морду авторам кода. И я не думаю, что такое возможно в сколь-нибудь существенно значимой библиотеке: обычно, прежде чем её отладят, установят определённые соглашения. Для подобной графики это порядок аргументов (x перед y, левый верхний до правого нижнего). Поэтому проблема подобного рода не должна возникать вообще. Если же кто-то произвёл подобную перестановку аргументов, то он должен и сменить название функции, чтобы исключить переходные проблемы.
То есть данный пример, на мой взгляд, надуман и нереален.
Вот вариация исходного примера более реальна — когда вместо содержания запроса передаётся его имя. Да, такое возможно при переделке API, и такое сложно ловить при компиляции. Вопрос совместимости API тут может быть неактуален, если все методы — только внутри. Но тогда должны быть и реальные тесты, которые сразу отловят ошибку.
V>А при явно заданных именах параметров было так: V>
V>И пофигу в каком там порядке идут параметры в объявлении функции. V>А вот читабельности такой подход, ИМХО, не прибавляет совершенно, только добавляя визуальный мусор. V>А насколько описанная мною проблема надумана, я не знаю. Я за то, чтобы было как в питоне: хочешь указывать — указывай, не хочешь — не указывай.
Согласен. Более того, это имело бы некоторые преимущества для языков типа C++: сейчас в нём можно указывать параметры только позиционно, а значения по умолчанию вводятся для "хвоста" вызова. Если иметь возможность задавать по именам, то получится возможность задавать значения только для тех параметров, которые действительно нужно переопределить в данном случае.
Точняк. А теперь представим себе, что выявляется доптребование такое, что waitUntilDone, или repeats, или isFirstRun перестают быть булевыми.
Что происходит с кодом в обоих случаях?
Для булевых аргументов — меняется структура кода, либо меняется сигнатура метода с добавлением кода.
Для констант (перечислений) — к существующему коду производится добавление нового кода.
И вот, с этой точки зрения, второй вариант выглядит правильным, а первый — костылем.
Много писанины, глазки устают. Пока сквозь это продерешься, очень много отвлекающих деталей. Это оправдано при вызове всяких CreateProcess, а так в большинстве случаев и так понятен смысл большинства параметров. И не всегда надо это знать.
Я для трудных случаев был бы полезен расширенный синтаксис, например, такой Ada-like:
Здравствуйте, x-code, Вы писали: XC>Здравствуйте, Mystic, Вы писали:
M>>Я для трудных случаев был бы полезен расширенный синтаксис, например, такой Ada-like: XC>Ada-синтаксис — это шутка что-ли?
Ну... имхо, похоже и в духе, см. именованное сопоставление.
Здравствуйте, Философ, Вы писали:
N>>В сложных случаях, да, оно полезнее. В простых — нет. Ф>Полезно во всех ситуациях. Ф>Не так давно правил багу, которую внесли при рефакторинге.
Ф>Вызов выглядел так: Ф>GetParameters(c_QueryReportName);
Ф>А сам метод выглядел вот так: DbParameter[] GetParameters(string QueryText)
Следующая бага подскажет и следующее улучшение: указывать еще и тип передаваемого параметра
Здравствуйте, Mystic, Вы писали:
M>Здравствуйте, Философ, Вы писали:
N>>>В сложных случаях, да, оно полезнее. В простых — нет. Ф>>Полезно во всех ситуациях. Ф>>Не так давно правил багу, которую внесли при рефакторинге.
Ф>>Вызов выглядел так: Ф>>GetParameters(c_QueryReportName);
Ф>>А сам метод выглядел вот так: DbParameter[] GetParameters(string QueryText)
M>Следующая бага подскажет и следующее улучшение: указывать еще и тип передаваемого параметра
... и мы вернулись к баяну 20-летней давности (system hungarian notation, чтоб её автору икалось. нет, это не Simonyi)
Здравствуйте, Mystic, Вы писали:
M>>>Я для трудных случаев был бы полезен расширенный синтаксис, например, такой Ada-like: XC>>Ada-синтаксис — это шутка что-ли? M>Ну... имхо, похоже и в духе, см. именованное сопоставление.
Мой вариант синтаксиса для именованных параметров: "контекстная область видимости", оператор "унарная точка" (такой оператор, кстати, можно было бы использовать и в некоторых других случаях).
// допустим, почти обычное "сишное" объявление функции
void Foo(int x=0,y=0,z=0) {}
// а вот так можно обращаться к локальным параметрам функции внутри круглых скобок при вызове функции.
Foo(.z=100, .y=200);
А стрелочку => нефиг тратить на всякую фигню, это идеальный по компактности и наглядности оператор для лямбда-функций и функциональных типов.