1. Java / Говнокод #12114

    +93

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    7. 7
    Float nan=Float.NaN;
    new Float(10).compareTo(nan);
    //-1
    nan.compareTo(nan);
    //0
    new Float(Float.POSITIVE_INFINITY).compareTo(nan);
    //-1. POSITIVE_INFINITY<NAN. LoL

    http://ideone.com/9WIo16
    Тут некоторые товарищи в соседнем треде предлагали сравнивать объекты через compareTo()==0, если возможно.
    Ну и беречься от equals как от огня, если есть Comparable.
    А вот к чему это приводит.

    Запостил: 3.14159265, 13 Ноября 2012

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

    • JavaGovno, перелогинься.
      Ответить
    • нанотехнологичненько
      Ответить
    • Говно в том, что NaN.compareTo(NaN) == 0?
      по-правильному должен всегда возвращать -1? :)
      Ответить
      • Кстати, ява считает, что nan.equals(nan) истинно.
        Ответить
        • Потому что это один и тот же объект.
          Ответить
          • Ну да, без объектов картина лучше:
            http://ideone.com/7Updlh
            Ответить
            • Рекомендую обновить оп-ссылку
              o.println(nan==nan);
              o.println(nan==nan1);
              o.println(nan==Float.NaN);
              Ответить
              • Тогда еще вот такую классику IEEE флоатов:
                http://ideone.com/23s0qg
                Ответить
        • Тем более. По-моему, код в топике ничего не демонстрирует, кроме того, что Java не может в NaN (http://ideone.com/QN2VZF). То, что NaN больше любого числа (он именно больше, NaN.compareTo(Inf) == 1) - тоже косяк.

          UPD: Поправка, Java Float не может в NaN http://ideone.com/qpPtqt
          Ответить
          • Нормально там все с NaN:
            http://ideone.com/RT1PxA
            http://ideone.com/MjDIFH

            Просто у compareTo() батхерт, т.к. число и не меньше и не больше и не равно, а вернуть то что-то надо. Хотя с другой стороны, наверное, можно было и экцепшн кинуть.

            UPD: Ну вот как всегда, пока набирал и тестил примеры, Роман уже успел обновить пост и написать об этом.
            Ответить
    • Что-то мне не нравится этот язык.
      Ответить
      • Покажите мне того, кому он нравится...
        Ответить
        • Авторам?
          Ответить
          • Ага. Почитайте чем сейчас Гослинг занимается.
            Жавой там и не пахнет.
            Ответить
            • Глубоководными роботами?
              Ответить
              • Угу. Пахнет разве что жабами.
                Кстати. А ведь жаб можно лизать.
                Ох прикроют говнокодик скоро, крепко прикроют.
                Ответить
                • Уходим запиливать глубоководных роботов в i2p?
                  Ответить
                • Можно лизать детей жаб, получать наркотические ощущения и убивать себя.
                  Ответить
                • >Ох прикроют говнокодик скоро, крепко прикроют.
                  откуда дровишки?
                  Ответить
                  • Ты хотел спросить "откуда взять таких жаб, чтобы в дровишки?"
                    Ответить
        • Zefick, azzclown
          Ответить
        • мне он нравится ;)
          Ответить
          • А раз он тебе нравится, ты пробывал ему признаться в этом? А вообще это плохой признак.
            Ответить
            • > ты пробывал ему признаться в этом

              Не надо. Мне так хаскель сердце разибил... Но я его добьюсь.
              Ответить
    • Авторы Float не осилили ни equals, ни compareTo
      Ответить
      • У compareTo() нет четвертого состояния - несравнимо. С equals() та же проблема.
        Ответить
      • А вот. Я понял.
        Давайте взглянем на это под другим углом.
        На самом деле, есть трабла поглобальней - никак нельзя быстро и красиво сравнить 2 Numbera.
        Если б они добавили всего-то одну строку в Number - implements Comparable<Number> и сделали в Number equals(x){return 0==compareTo(x);} - всё было б проще.

        Но они этого не сделали. Почему?
        http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4414323
        Ответить
        • С контравариантностью вообще нужно быть осторожным. IMHO, нужно стараться проектировать так, чтобы было T extends Comparable<T> (а не Comparable<SuperT>). Опять от наследования сплошные проблемы...
          Ответить
        • А вот кстати. Допустим они все это реализовали. И теперь у нас equals может сравнить два любых number'а. В стандартных классах можно запилить пачки кастов и сравнений для конкретных типов. А вот как быть с нестандартными классами, которые будут добавлены только потом? myNumber.equals(floatNumber) я еще до ума доведу, а вот обратное ему floatNumber.equals(myNumber) - хрен там. А некоммутативное equals() не есть гуд.
          Ответить
          • а)Можно было запретить писать своих наследников для Number.
            > а вот обратное ему floatNumber.equals(myNumber)
            б) есть как бы интерфейс. правда херовый, но идея понятная - привести всё к общему знаменателю.
            если ты херово переопределил
            public abstract double doubleValue();
            это твои проблемы

            Вот это очевидное поведение new Byte(2).equals(2) //false
            Гораздо ужасней, чем предполагаемые "свои" имплементации.
            Они такие все умные в EJ и других книжках, а в коде - говно, треш и пиздец.
            Ответить
            • > public abstract double doubleValue();
              Для длинных целых чисел это весьма хуевый интерфейс. Вот разве что свести все к Rational'ам, и окончательно забить на скорость...
              Ответить
              • Ну да. Но ведь могли уже сто раз сделать Rational. Там ниче не менялось since 1.4. Прикрутить сей интерфейс к Int,Long,Byte,Char и прочим - дело 5 минут. Double, Float - идут лесом.
                Заодно решить известные проблемы с плавающими диапазонами.

                >Для длинных целых чисел это весьма хуевый интерфейс.
                Даже если б там epsilon поставили - я был бы рад.
                >скорость
                Java. Не смешите.

                Просто им похуй.
                Ответить
            • > new Byte(2)
              Тут еще веселее. Это вообще не скомпилится.
              Ответить
              • Подумаешь. Ну не написал каст.
                Еще можно так : Byte.valueOf ( "2" ).equals(2) //false
                Byte.valueOf ( "2" ).equals("2") //wtf?
                Ответить
                • Ага. Вроде и документировано, что Byte можно сравнивать только с Byte, но вот неприятный осадок всеобщей недоделанности остается.
                  Ответить
                  • Срань. Нубам вбивают в голову - не пишите ==. Сравнивайте через equals(). По началу всё работаёт.
                    Потом лезет NPE. Нуб быстро запоминает - надо ставить проверку. Или стиль использовать магистра Йоды.
                    Всё работает хорошо. Более никто ничего не говорит. Правило крепко усаживается в голове.
                    А потом начинаются исключения, где ни ==, ни equals корректо не работают или надо таки сравнивать через ==
                    Ответить
                    • Самый эпичный equals все-таки у java.net.URL... Вот он рвёт все шаблоны.

                      P.S. Надо бы на ведроиде попробовать сравнить два URL'а. Интересно, выдаст ли он на эту хуиту NetworkInMainThreadException или нет.
                      Ответить
                    • Забавно. Видимо ребят из гугла заебала это джавоблядство, и они сделали вот так:

                      This problem is fixed in Android 4.0 (Ice Cream Sandwich). In that release, URLs are only equal if their host names are equal (ignoring case).
                      Ответить
          • Почти наверняка на уровне байткода можно объявить метод специализирующийся на уже существующем классе, типа как в Шарпе static Method(this foo, ...).
            Ответить
            • К чужому классу емнип метод никак не прикрутить.
              Ответить
              • Хз. Я жабий байткод не знаю почти совсем, но знаю, что флешевый сваяли по аналогии, а там такое можно, если захотеть. Тут только вопрос, описаны ли эти методы как и все остальные, или они как-то специально в самой виртуальной машине хранятся.
                Ответить
                • На StackOverflow вот так пишут:
                  It's not simple. Once a class is loaded by a classloader, there is no way to change the methods of loaded classes. When a class is requested, a classloader will load it and link it. And there is no way to change the linked code or to add/remove methods.
                  ...
                  We can't add or remove fields too.
                  Ответить
                  • Ну байткод изменять после загрузки - это уже как Боржоми, очень поздно...
                    Ответить
                    • Ну а правка байткода до загрузки равносильна подмене системных либ своими. Что тоже ужасно (хотя и вполне реально).

                      В жабе просто принцип: 1 класс - 1 файл. Он не нарушается даже для вложенных и анонимных классов. Поэтому подмешать какие-то методы в чужой класс без его перекомпиляции нереально.
                      Ответить
                      • Ну... тогда никак, наверное :)
                        Честно, я не знаю, как именно организован байткод, но скорее всего есть какое-то "квалифицированное" имя, которое определяет откуда берется метод, и каким образом он относится к тому, на чем специализируется. Если скомпилировать еще один с именем сконструированым по такому же принципу - то почему бы и не заработать? Классов же как таковых нету в байткоде, это превращается просто в имена методов каким-то образом распознаваемые рантаймом как принадлежащие тому же классу. Хз. просто нет достаточно рвения попробовать подсунуть фейк со специализацией на том же объекте, что и системый класс.
                        Ответить
                        • В .class файлах, емнип, имена методов хранятся в неквалифицированном виде. Поэтому очень маловероятно, что загрузчик пропустит метод, в котором к имени дописали левую фигню.
                          Ответить
                          • зато можно поудалять ссылки на старый класс, убить его вместе с ClassLoader'ом и загрузить новый.
                            я как-то баловался таким, организовывал перезагрузку классов в рантайме (каждый раз проверялось, не изменился ли класс, если да, то загружался заново)

                            основная трабла тут со ссылками и сборкой мусора, запросто схватить OutOfMemoryException: PermGen space

                            зато, внимание, основная киллерфича: один и тот же класс можно загрузить разными ClassLoader'ами (чей использовать, решает загрузчик, который загрузил класс, метод обьекта которого сейчас выполняется)
                            Ответить
                            • > зато можно поудалять ссылки на старый класс
                              В данном сферическом треде - поудалять все ссылки на Integer... не прокатит походу.
                              Ответить
                            • Да. Есть такая утечка памяти. Особенно легко наткнуться в J2EE среде.
                              Вот посоны решили
                              http://www.jarvana.com/jarvana/view/com/alibaba/citrus/tool/antx-autoexpand/1.0.10/antx-autoexpand-1.0.10-sources.jar!/org/apache/commons/beanutils/ContextClassLoaderLocal.java?format=ok

                              http://commons.apache.org/beanutils/apidocs/org/apache/commons/beanutils/ContextClassLoaderLocal.html
                              Ответить
                • > как-то специально в самой виртуальной машине
                  В C# экстеншен-методы преобразуются компилятором в вызовы статических методов, скорее всего, в флеше что-то аналогичное.

                  Для жабы есть AOP, но это не совсем то.
                  Ответить
                  • Нет, во флеше все методы (если это методы класса, т.е. с первым аргументом this) просто записываются в том же пространстве имен, что и класс, на котором специализируются. Чтобы получить ссылку на класс в this первым опкодом в функции идет OThis - и это все, что требутется для того, чтобы функция стала методом.
                    Ответить

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