От известно време установих, че не пърхам от радост като видя функция
с булеви параметри. Извикването изглежда особено неясно:
<code>
do_something("string", true, true, false)
</code>
Да оставим че параметрите са повече от желателното. Какво правят
горните флагове? Трябва да се гледа документацията, трудно се помни, и
тн.
Решение номер 1: константи или енъми. Не ми харесва, защото пак не се
помнят лесно, пък и утежняват положението.
Решение 2: (руските колеги го правят, говорим за руби). дефаултва
параметъра до false, и подава символ. Донякъде е добре, само че остава
именоването на символа на въображението на потребителя.
<code>
def eat(fruit, with_leaves = false) ... end
eat(apple, :with_leaves)
</code>
Решение 3: Хеш. В релсите като е ли са така. Обаче пък е екстремно,
особено ако е един параметър. Пък и разваля сигнатурата на метода, пак
имаш нужда от документацията. А и някакси товари имплементацията.
<code>
def eat(fruit, options = {})
options[:with_leaves] ||= false
... end
eat(apple, :with_leaves => false)
</code>
Решение 4: Named parameters. Чич' Джим (автора на рейката) говори за
такъв тип рефакторинг, където чупим зависимостта на поредността на
параметри, за сметка на имената. В ruby 1.9 вече ще дойдат (ако влезе
в масова употреба преди Софи Маринова да се ожени за сина си за
пореден път). Което май най така добре ми действа на слуха и на
зрението.
Проблем ли е това според вас?
Скоро и аз се спънах в това достатъчно сериозно, че да се замисля. И
аз не обичам ttftftftft поредиците. Иде ми да ги заменя с побитови
маски.
>...
>
> Решение 2: (руските колеги го правят, говорим за руби). дефаултва
> параметъра до false, и подава символ. Донякъде е добре, само че остава
> именоването на символа на въображението на потребителя.
>
> <code>
> def eat(fruit, with_leaves = false) ... end
> eat(apple, :with_leaves)
> </code>
>
И аз съм в този отбор. Отчасти защото в PHP другите методи са още по-грозни.
Моята аргументация:
http://codex.wordpress.org/WordPress_Coding_Standards (най-отдолу)
Два реда документация решават проблема с въображението. Случва се
понякога някой да сбърка една буква и да се чуди известно време какво
се случва. Ако не ме мързи проверявам дали аргумента в списък
(частичен, гъвкав и несемантичен enum).
> Решение 3: Хеш. В релсите като е ли са така. Обаче пък е екстремно,
> особено ако е един параметър. Пък и разваля сигнатурата на метода, пак
> имаш нужда от документацията. А и някакси товари имплементацията.
>
Изричен хеш само ако имаш много аргументи.
> Решение 4: Named parameters.
> ...
> Което май най така добре ми действа на слуха и на зрението.
>
О, да. Не знам дали си цъкал python, ама там да ти е кеф да си
параметризираш функциите.
По тази точка аз тъжен:
http://www.php.net/~derick/meeting-notes.html#named-parameters
Happy hacking,
Н.
2009/11/27 Stefan Kanev <stefan...@gmail.com>:
> Това много зависи от конкретната функция. Твърдо против булеви параметри
> които вкарват логическа кохезия съм. Колкото до решенията ти.
> 1. Нито константи, нито енъми не ми харесват. So C.
> 2. Това със символа е хитро. Не знам как си влияе на рефакторинка, обаче. Не
> знам и какво става ако имаш повече от един и искаш да подадеш само втория
> 3. Хеш ми харесва най-много.
Ем и на мен ми харесва, ама пак са недоклатени named parameters
(именовани или именувани параметри?). Между другото, и JavaScript-a
страда от същия проблем. Гледах скоро кода на jqGrid, две страници код
за сетване на параметрите.
> 4. В Ruby 1.9 няма named parameters. Объркал си се. Това е специален
> синтаксис за хеша.
>
> На базата на параметрите, аз бих си помислил да вкарам това в малко обектче
> с attr accessor-и, за да можеш да правиш така:
> collector = DataCollector.new :include_blanks => true
> collector.escape_html = false
> result = collector.execute
> Повечко код е, но е доста по-прозрачно и има повече fail-safe. Допълнително
> ти имаш и обект, което си е плюс. Разбира се, предпочитам да ги държа до
> минимум.
Абе да имаш обект чак да е плюс винаги...
[self.navigationController pushViewController:registerViewController
animated:YES];
Функцията pushViewController пък се дефинира така
- (void) pushViewController:(UIViewController *)controller animated:
(BOOL)isAnimated
{
}
Тва примерно, по памет. Както виждаме параметрите имат тип, име и
_label_. Това въпросното animated: е всъщност label-a. А пък името на
функцията е label-a на първия параметър. Страшно удобно и за функции с
много параметри става адски удобно като се пише
[object functionName:param
withTitle:@"Some title"
andX:10
andY:10
andZ:20];
Също няма true и false, а има YES и NO.
С две думи, кой как се уредил.
А за enum-ите - може да са C-подобни, но поне да не са all-caps. Като
видя нещо от рода на
TT_ROW_HEIGHT
TT_TOOLBAR_HEIGHT
и ме фаща разстройство :))))))
On 27 Ноем, 10:31, Nikolay Bachiyski <n...@nikolay.bg> wrote:
> 2009/11/27 Petyo Ivanov <under...@gmail.com>:
Абе да имаш обект чак да е плюс винаги...
Това аз го знам като логическа кохезия от Code Complete. Напълно сългасен съм че е зло и твоето е добър refactoring. Обаче не винаги наличието на булев параметър е зло. Ето ти един пример.def search_for(phrase, load_bodies = false)solr.query :q => phrase,:qf => (load_bodies ? 'title' : 'title body'),:hl => true,:fq => 'published_at:[%s TO *]' % 1.month.ago.iso8601endendИмаш full-text търсачка, искаш да получаваш заглавията на статиите, които търсиш. Понякога искаш да получаваш и съдържанието на статията. solr в горния код е обект който идва от бибилотека (rsolr) и това е начина да го интерфейсваш. Кратките имена идват от, отново, от search engine-а.Въпроса е -- наистина ли има смисъл да изваждаш това в два отделни метода? Всичко което ми хрумва съдържа повторение или е ненужно сложно за този пример.
А, не ти позволявам да monkey patch-ваш String-а по тоя начин. Не му е работа да знае за query.
Въпроса е, че при мен има повече от два атрибута (keywords и load_bodies). Докато си само с тези двата, си мисля че е по-чисто да са аргументи. Това минава в Ruby относително добре. Като се замисля, дори да го пишех на Java, пак щях да го направя по тоя начин.
Но да, и моята мисъл беше, че няма универсална формула, само принципи които трябва да се прилагат в контекст. Затова и мрънкам да давате конкретни примери като говорите за такива неща :)
Не изчетох цялата тази поредица, защото не съм запознат с вашите
любими езици за програмиране. От гледната точка на Java, а и на това,
което съм чел за interface design-а, бих казал, че е доста по-добре да
се ползват два метода с ясни имена, отколкото метод с допълнителен
boolean параметър.
Enum-ите, поне в Java, са също добро решение, особено в случаите,
когато допълнителният метод само усложнява нещата.
Поздрави,
Иван
Е не съм седнал да подменям length метода, че да ти е толкова гадно. Представи си, че съм малък YAML библиотечък, който ти е сложил метод to_yaml (както е направил един такъв в мойто руби). А и ако не искаш, опцията със статичния метод на Query си остава. Аз съм свикнал на екстендване покрай езиците където това е измислено така, че да не можеш да настъпиш другарчето по пръстите (най-вече C#).
Не знам и какво да мисля за идиома, в който (привидно) добавяш метод към съществуващ клас. В Objective-C има такава опция, не съм имал възможност да я проуча в реални условия. Интересно ми е дали срещаш някакви проблеми с това, като го правиш в C#. Първия ми инстинкт като видя someObject.foo() е "Хм, класът на someObject имал метод foo()". Туко виж бих си помислил, че е част от SomeObjectClass, пък той бил локално разширение. Може би IDE-то ги оцветява или нещо.