1. Perl / Говнокод #12980

    −103

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    7. 7
    8. 8
    9. 9
    sub exdef {
        my ($hash, $key) = @_;
    
        if (exists $hash->{$key} && defined $hash->{$key}) {
            return 1;
        }
    
        return 0;
    }

    No comments.

    BTW.
    http://perldoc.perl.org/functions/exists.html
    http://perldoc.perl.org/functions/defined.html

    Запостил: Elvenfighter, 08 Мая 2013

    Комментарии (32) RSS

    • В чем суть, поясни.
      Ответить
      • Проверяется одновременно существование ключа в хэше и что его значение определено. Ваш кэп :)
        Ответить
      • Хватило бы просто проверить на defined
        Ответить
        • В смысле результат функции будет всегда равен

          defined $hash->{$key};
          Ответить
          • Я просто думал что вызов defined для несуществующего ключа в hashref будет давать ворнинг, оказалось что нет.
            Ответить
          • Если в хеше ключа нет, то при проверке defined $hash->{$key} он будет создан. В некоторых случаях autovivification нежелательна( например, в SQL::Abstract добавится проверка "where fieldX is null" ). Предварительная проверка exists решит эту проблему.
            Ответить
            • Ямщик, не гони лошадей: https://ideone.com/synEH8.

              autovivification, насколько я понимаю, срабатывает в случаях, когда нужно получить доступ к следующему уровню хеша - т.е. defined $hash->{'a'}{'b'} добавит ключ 'a' в $hash. Но ключ 'b' добавлять не будет. В нашем же случае он ничего не добавит, т.к. autovivification не действует на последний уровень.
              Ответить
    • Вообще, это не говнокод. Возьмите да и замерьте скорость через Benchmark exists vs defined. А теперь представьте, что мы фильтруем огромное количество невалидных ключей.
      Ответить
      • А какого, простите, хуя в перле defined для невалидного ключа работает медленнее, чем exists? И как вообще связка exists+defined на перле может работать быстрее, нежели сам defined? Он же в сишной части всяко и начинается с поиска переменной (аля exists), а затем уже идет проверка значений (которую мы все равно будем делать, если переменная существует). Если defined для несуществующих ключей работает дольше чем exists, и этот код не говно - значит говно в интерпретаторе...
        Ответить
      • P.S. Бенчмарк: http://www.perlmonks.org/?node_id=488777

        Но данный бенчмарк не совсем подходит, т.к. здесь тестируются defined и exists по-отдельности. exists не спаренный с defined естественно будет работать быстрее, нежели defined, тут я не спорю, в defined'е чуть больше проверок.

        Но пара exists+defined написанная на перле ну никак не может быть быстрее, чем defined, полностью написанный на си.

        Глупости какие-то пишете.
        Ответить
        • Хорошо, был не прав. Однако: http://perldoc.perl.org/perlop.html#C-style-Logical-And

          Используется and, но с && тоже самое: http://pastebin.com/kZKeVAe9

          Rate exdef defined exists
          exdef 2994012/s -- -35% -40%
          defined 4608295/s 54% -- -8%
          exists 5025126/s 68% 9% --

          Проценты варьируются +-10% от запуска к запуску, но дабы побыстрее.
          Ответить
          • > Однако
            Да я прекрасно знаю, что && он short-circuit. Поэтому я и написал, что в случае когда ключ не определен, то defined+exists в принципе догонит exists по скорости (равно как и одинокий defined, в котором подобная логика все равно есть).

            > -40%.
            Ага. Т.е. exists+defined мало того что говно, так еще и медленное? ;)
            Ответить
            • Вобщем, коротко, правильно писать всегда так:

              if (exists $hash{x}) {
                if (defined $hash{x}) {
                  ...
                }
              }


              Тем не менее, не смотря на то, что кажется на говнокода такая проверка нужна порой: высоконадежный софт всегда с использованием use warnings.

              Прокачили скилл и это хорошо :)
              Ответить
              • Правильно, имхо, юзать один из способов в зависимости от цели:
                if ($hash{x}) - exist, defined, true
                if (defined $hash{x}) - exists, defined
                if (exists $hash{x}) - exists
                Все франкенштейны, составленные из них только работают медленнее, и выглядят запутаннее.

                Какие еще варнинги?! Мы же не передаем никуда этот элемент, а только проверяем на определенность: https://ideone.com/65cORh.

                UPD. Если передавать - конечно будут https://ideone.com/HZl7K6. Но вот только defined тут совершенно не причем.
                Ответить
                • Главное решается autovivification. С другой стороны, как я говорил в самом начале и если бы работал short-circuit как положено, то прирост в скорости когда 50% идет тест на не валиды, то вариант exists + defined выйгрывает в скорости от defined ~ 25%.

                  Так что логика верная, но верить перлу нельзя никогда. Бенчи-бенчи-бенчи :)
                  Ответить
                  • Мда. Вот а вообще очень плохая тендеция намечается.

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

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

                    Так вот и получается, что низкоуровневый язык по сути дает более понятный код, нежели высокоуровневые, за счет того, что в погоне за скоростью высокоуровневый код превращают в говно...

                    P.S. Хотя, скорее всего, проблема со скоростью defined'а надуманная, т.к. он занимает всего 96нс, а тот же цикл вокруг него и т.п. запросто могут занять больше времени чем все эти проверки...
                    Ответить
                  • > Бенчи-бенчи-бенчи :)
                    Кстати, а профайлер в перле есть? Чтобы править не то, что кажется медленным, скатывая код в говно, а видеть именно хотспоты?
                    Ответить
                    • Devel::NYTProf
                      Сам не пользовался им никогда.
                      Ответить
                      • > Сам не пользовался им никогда.
                        Почему? Профайлеры же очень годная штука, позволяющая расставить приоритеты по оптимизации кусков проекта... Мне нравится для крестов его юзать ;) Экономит просто гору времени...

                        P.S. А без профайлера можно всю жизнь менять " на ', думая, что они работают быстрее. А на деле это даст жалкие 2% прироста производительности, которые нафиг никому не сдались, если можно выиграть в другом месте все 200...
                        Ответить
                        • >Почему?

                          Пока руки не дошли. Сейчас вот смотрю видео про nytprof: http://blip.tv/timbunce/devel-nytprof-v4-oscon-201007-3932242
                          Начну пользоваться. Тут еще зависит где работаешь и как работаешь :) У меня последнее время было - пиши код, главное надежность, а оптимизации шли в последнюю очередь. Вопрос надежности кода в перле не менее увлекательное занятие чем профилирование, я уверен. Особенно с XS-кодом.
                          Была бага в одном модуле, утечка: пока искал, 4 раза переписал свое приложение (ушел почти месяц), стопитсот раз оптимизировал, а потом решил удалять все потихоньку, нашел бажный модуль. Запустил valgrind - ничего, gdb - куча кишков на си, считаю ref counts.. Задумался на 10 минут, прикинул где и куда может течь - исправил одну строчку и нет утечек :)
                          Ответить
                          • > главное надежность, а оптимизации шли в последнюю очередь
                            Респект ;)

                            > Вопрос надежности кода в перле не менее увлекательное занятие чем профилирование
                            Вот поэтому для меня перл так и останется языком для мелких говноскриптиков, которые я люблю на нем писать ;)

                            > решил удалять все потихоньку
                            Кстати, судя по опыту, самый эффективный способ поиска гейзенбагов.
                            Ответить
                          • А вообще у меня к перлу двоякое отношение:

                            Для мелких скриптов - язык очень приятный. Пишутся быстро, работают достаточно шустро. Модулей хороших на CPAN'е полно.

                            Но вот стоит начать писать что-то чуть-чуть побольше, даже с парой-тройкой своих модулей, как все достоинства перловки сразу же превращаются в почти фатальные недостатки... Те же классы у меня, к примеру, вызывают отвращение. Конструкции типа $hash->{$key} начинают выбешивать, т.к. даже в крестах это просто hash[key] или struct.field. А те приятные фишки, которые юзались в маленьком коде, юзать страшно, т.к. поддерживать их потом сложновато...

                            В итоге более-менее надежный код по логике откатывается к си\с++\жабе, а по синтаксису получается намного хуже и длиннее чем на тех самых языках ;(
                            Ответить
                            • >Но вот стоит начать писать что-то чуть-чуть побольше, даже с парой-тройкой своих модулей, как все достоинства перловки сразу же превращаются в почти фатальные недостатки...

                              Ну это тебе так кажется. Кода на си для чего-то очень серьезного, скажем для того же DBD::Oracle у тебя на си получится в разы больше. Ладно, скажешь что заюзаешь потоки и этим выйграешь в скорости. Но допустим можно в перле будет воспользоваться форком и тогда перл покажет все свои прелести.

                              Я писал разные приложения. Средний размер сейчас у меня от 500 до 1500 строк. Самое большое овер 10 тыс. строк на одно приложение, несколько десятков модулей и куча функционала: snmp, telnet, логирование на уровне log4j, работа с БД, использование кэшей и т.д. и т.п. Писалось в довольно короткие сроки (месяц с лишним) - почти 3 тыс строк, функционал сейчас наращивается вообще влет. А на си сколько бы я это отлаживал? :)

                              Вообще судя по тому как тот же Tim Bunce (автор DBI, DBD::Oracle, Devel::NYTProf) рулит и педалит своей компанией, я бы не сказал, что на перле нельзя писать что-то сложное. Можно, только чтобы стать как он надо знать си, мозги, потратить н-лет на разработку в разных проектах и может тогда что-то дельное получится.

                              Есть еще относительно новый чел - Mark Lehmann (AnyEvent, EV, libev - аналог libevent). Этот чел вообще маньяк :) С его уровнем знаний си(++) вроде как перл ему и не нужен. Но как видно - пишет и очень активно.

                              Это к тому, что тот кто считает, что перл мертв и для неудачников - просто не умеют его как следует готовить, имхо. И да, си рулит везде.
                              Ответить
                              • Ну я не говорю, что язык плохой ;)

                                Ну и си все-таки сравнивать не совсем корректно, немного не тот уровень. А вот тот же с++ по поддерживоемости будет ну никак уж не хуже перловки.

                                Про опыт согласен. Прокачанный программист на своем языке может творить чудеса...

                                А напомните, пожалуйста, чем там форк отличается? Там не системный, а свой планировщик, и можно запустит под сотню таких "процессов", если они не будут зависать в сишном апи? Если ьак то да, на си это проблематично. На крестах - boost::asio с подобными задачами споавлется. Но там асинхронная лапша со всеми вытекающими. Зеленые треды все-таки поприятней.
                                Ответить
            • >Да я прекрасно знаю, что && он short-circuit.

              Вы не поняли. Short-circuit не работает в этом случае. У меня 5.12.4 из поставки Debian Squeeze. Если взглянуть на код ниже, как я показал разделить в два if'а, то мой бенч показывает отставание от exists в 4%.

              ..................Rate  exdef_br     exdef   defined exdef_cmp    exists
              exdef_br  10869565/s        --       -1%      -22%      -38%      -40%
              exdef     11013216/s        1%        --      -21%      -37%      -40%
              defined   13927577/s       28%       26%        --      -21%      -24%
              exdef_cmp 17543860/s       61%       59%       26%        --       -4%
              exists    18248175/s       68%       66%       31%        4%        --
              Ответить
              • Хм. Т.е. версия разбитая на два ифа работает быстрее нежели сам defined? Вот я всегда догадывался, что рантайм перла говно... Но теперь я полностью в этом убедился...
                Ответить
                • Там был набор 100% невалидов, что логично. С 100% валидами тормоза exists + defined vs defined почти в 2 раза.
                  Не могу найти баг в трекере, видимо надо постить.
                  Ответить
          • Это еще интереснее: [url]http://pastebin.com/TXeRnEdu[/url]

            Rate    exdef exdef_br  defined   exists
            exdef    10288066/s       --     -10%     -26%     -33%
            exdef_br 11494253/s      12%       --     -17%     -25%
            defined  13888889/s      35%      21%       --     -10%
            exists   15384615/s      50%      34%      11%       --


            :)
            Ответить
            • А почему от скобок скорость зависит? Или версия без скобок изначально кривая из-за приоритетов?
              Ответить
              • Это runtime. Судя по всему проверки начинаются справо налево. Т.е. в exists ожидается хэш, но сначала, видимо, идет boolean/строка/число (в перле все одно и тоже :).
                Вообще писать без скобок все подряд считается плохим стилем by design. Ну и для общего развития, трудности перла, описаны [url=http://www.perlmonks.org/?node_id=663393]тут[/url]
                Ответить
                • > Вообще писать без скобок все подряд считается плохим стилем by design
                  Вот за это плюсану. Я в перле всегда пишу скобки. Абсолютно всегда. В конце концов набираю я быстро, парсер у перла достаточно шустрый, и 2 байта ради непонятно чего экономить совсем влом.
                  Ответить

    Добавить комментарий