Conversation
first project
Прокоментировал, ждем исправлений! :) Если у вас какие-то вопросы - не стесняйтесь открывать тему в обсуждениях на хекслет, писать мне на почту или же тут в коментариях. |
изменил метод для мутации и убрал дублирующееся объявление временного массива
#define ATGC @[@"A", @"T", @"G", @"C"]
Исправил недочёты на которые мне указали
main.m: Категорию mutator желательно реализовать в отдельных файлах. Cell.h(11): Cell.m(15): Cell.m(20): Cell.m(48): Cell.m(50): |
За Делаем гденить в цикле i+=чтонить и бам мы за пределами. Супер, безудержное веселье =) |
А не надо в теле цикла делать i+=чтонить :) Все равно i не видно вне тела цикла, а для прерывания итераций есть break. Для i+=чтонить есть, например, более подходящий while. Если уж очень надо, всегда можно написать <, а запись != подчеркивает строгость условия. |
@arabesc Нет, если речь идет о простом переборе, то только |
@aspcartman, вывод Ваш совершенно никак не следует из предыдущего абзаца. Если это простой перебор, то тем более нет никаких причин перескочить за границу цикла. |
Условие должно задавать некоторую область, выход за пределы которой должен вызывать окончание цикла. Вы предлагаете для того, чтобы проверить исправность подвески расшатать в велосипеде гайки. Аргумент "и так должно работать" или "это поможет заметить багу" не существенны.
Может быть даже упадет где-то рядом с телом - понравилось. =) Ага. Щас. Программа с большей вероятностью побьет данные. Если такой код уйдет в релиз и из-за него кто-то потеряет важные данные - вам будет очень плохо. Очень, и лучше не проверять. Так-же это прекрасная дырка для очередного эксплойта. Программирование это достаточно строгая наука, давай-те в матане интегрировать по области так-же? =) В темуВот еще пример небезопасного кода, специально сбегал за слайдами институтских лекций, думаю полезно будет. /* Участок памяти ядра содержит данные доступные пользователю */
#define KSIZE 1024
char kbuf[KSIZE];
/* Копируем не более maxlen байт из области ядра в буфер пользователя */
int copy_from_kernel(void *user_dest, int maxlen) {
/* Счётчик байт len – минимальное из размера буфера и maxlen */
int len = KSIZE < maxlen ? KSIZE : maxlen;
memcpy(user_dest, kbuf, len);
return len;
} Вроде бы все прекрасно, да? Ничего не предвещает беды. Типичное использование: #define MSIZE 528
void getstuff() {
char mybuf[MSIZE];
copy_from_kernel(mybuf, MSIZE);
printf(“%s\n”, mybuf);
} Однако же что будет, если мы поставим перед MBSIZE минус? copy_from_kernel(mybuf,-MBSIZE); А вот что - memcpy берет как аргумент С вашим i != 10 можно тоже придумать много примеров, когда программист зазевается и не заметит возможность перескока, как не заметили разработчики ядра FreeBSD (откуда этот кусок и выдран), а ведь люди не глупые. |
Программа, это не механизм, где есть материалы и сопромат, это детерминированный алгоритм, поведение которого должно быть подчинено логике, а не складываться из совокупности широких допущений, что не исключает возникновение ошибок, но лишь несколько снижает вероятность их проявления. Т.е. это такая своеобразная "хорошая мина при плохой игре" - ошибки внутрь программы прокрались, курсируют по структурам данных, но до поры получается их скрывать.
Не "и так должно работать", а "именно и только так должно работать". Если случилось что-то другое, а разработчик этого не хотел, значит, проблема должна проявиться как можно скорее, чтобы ее можно было решить в зародыше, а не тихо размазаться в недрах программы. Про ненужность "это поможет заметить багу" тоже понравилось :) Вы должно быть и ассерты не ставите?
По Вашей логике получается, что пусть лучше программа уйдет в релиз с незаметным багом и долго по чуть-чуть в редких и непонятных ситуациях будет портить данные пользователя, чем обнаружит свои недостатки максимально быстро и явно, может даже еще на этапе QA.
И сами себе противоречите. Пишете про строгую науку, но защищаетесь от каких-то чудес, когда детерминированный алгоритм вдруг начнет себя вести не так, как ему предписывал разработчик.
Не пришлось дочитывать до этого места, чтобы понять, где подвох. Вы предлагаете грубые ошибки не выявлять на раннем этапе и исправлять путем правильного дизайна программы и верификации ее данных, а амортизировать ущерб от них путем расстановки бесчисленных смягчающих возможные негативные последствия проверок? |
Вам не кажется, что вы излишне экстраполируете? Мне, и не мне одному, видится что вы притягиваете аргументы за уши. Действительно, проблема должна по хорошему выявиться в зародыше. Но когда она уничтожит данные - будет уже поздно. Когда я ставлю четкие условия я знаю, что i никуда за границы дозволенного не выйдет при новой итерации, особенно это важно если внутри цикла она притерпевает изменения. И давайте не будем переходить на личности, это не красиво и только мешает (я про ассерты) =). Стоит определить четкие критерии, по которым можно сравнивать подходы. Ваша аргументация дает подходу право на жизнь, но я бы не советовал его и сам бы не начал использовать, тк он может привести к потере важных данных в случае чего, и никого не будет волновать, что это вы так багу ловите, на живца. А ведь бага может всплыть и не от вас, а от сторонней либы, части которой использовались в цикле. Нет, данные пользователя - святое. На баге мы должны либо вывалиться, либо оперативно его обработать, если это возможно. Ваш подход если и помогает вывалиться, то за счет данных, а это, считаю, не допустимо. От @2k00l
На пункт 4 думаю стоит закрыть глаза. |
Не кажется. Я вам про простой перебор, где != достаточное условие, а мне в ответ про чудеса с внезапно прыгающим счетчиком, где < уже необходимое условие.
Кто здесь?!
Вы не ставите четкие условия, вы надеетесь, что проверка сработает в случае нештатной ситуации и амортизирует проблему, возможно, полностью нивелирует, но не факт. Преждевременный выход из цикла может означать, что не вся запланированная информации окажется обработана, а это может привести ко все той же порче данных, отказу в обслуживании. Доказать, что где-то данные портятся больше, где-то меньше, вряд ли можно.
Я написал исходное сообщение в контексте простого перебора, экстраполировать на все подряд начали вы. И повторю, если переменная, от которой зависит количество итераций, непредсказуемо меняется в теле цикла, то лучше использовать while, это нагляднее читается. |
Здесь - команда hexlet в неполном составе =) Похоже я действительно экстраполировал сам. Да, если внутри цикла i не должна изменятся и имеет стандартный шаг - то метод себя, должно быть, оправдывает. Контраргументов не вижу, кроме ухудшения читаемости и случая с избитием данных при пропрыге из-за непредвиденных обстоятельств =). |
Ой мы тут в коммите у @Dronnn устроили. Не хорошо. |
Наверное, еще и письмами с уведомлениями заспамили :) Можно поудалять лишнее, вроде более менее к консенсусу удалось прийти. |
Да думаю пусть будет, если владелец не против. Пусть люди читают :) |
По теме, @Dronnn: Cell.m(50):
если precentM равен 0, итераций быть не должно. Алгоритм mutate рабочий, но не очень красивый. Представьте, что при заданной 100% мутации обработано вот уже 99 индексов, но никак не выпадает нужный 100-й, сколько может быть пустых итераций? Не так много, конечно, но это процессорное время. Если есть желание, подумайте над алгоритмом получше или посмотрите в других работах, на оценку это все равно не влияет. |
Замечание номер раз: Хорошо бы все же реализовать категорию mutator в отдельных файлах. Ответ: Так было сделано на лекции. Поэтому я и сделал так. Результат: Исправлено. Замечание номер два: наличие глобальной переменной заданию не противоречит, но является не совсем удачным подходом с точки зрения ООП. Ответ: Сделать глобальную переменную мне посоветовал один из проверяющих. В книге Аарона Хилегаса "Objective-C. Программирование для iOS и MacOS" использование глобальных переменных вполне допускается и даже рекомендуется, например, как замена #define Результат: Исправлено. Метод mutate: полностью изменён.
Привет. Замечание номер два: наличие глобальной переменной заданию не противоречит, но является не совсем удачным подходом с точки зрения ООП. Метод mutate: полностью изменён. |
Можно сделать глобальную статическую переменную в Cell.m, таким образом, доступ к ней будет только в контексте Cell. Если потребуется доступ к этим данным снаружи, например, из категории mutator при реализации в отдельных файлах, можно в Cell добавить статический метод (метод класса), возвращающий указатель на данные. |
first project