1. Куча / Говнокод #11813

    +127

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    /**
       * Determines equality based upon the contents of this Box instead of the box itself.
       * As a result, it is not symmetric. Which means that for
       *
       * <pre name="code" class="scala">
       *     val foo = "foo"
       *     val boxedFoo = Full(foo)
       *     foo == boxedFoo //is false
       *     boxedFoo == foo //is true
       * </pre>
       *
       * For Full and Empty, this has the expected behavior. Equality in terms of Failure
       * checks for equivalence of failure causes.
       */
      override def equals(other: Any): Boolean = (this, other) match {
        case (Full(x), Full(y)) => x == y
        case (Full(x), y) => x == y
        case (x, y: AnyRef) => x eq y
        case _ => false
      }

    https://github.com/lift/framework/blob/master/core/common/src/main/scala/net/liftweb/common/Box.scala

    Запостил: rat4, 20 Сентября 2012

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

    • А я-то голову ломал, какого художника сравнение не работает...
      Ответить
    • Это чего же накуриться надо, чтобы такое написать. В стандартной библиотеке же нормально...
      scala> val box = Some("x")
      box: Some[java.lang.String] = Some(x)
      
      scala> box equals "x"
      res0: Boolean = false
      
      scala> "x" equals box
      res1: Boolean = false
      Ответить
      • full - синоним some?
        Ответить
        • Я про Full(x) спрашиваю. Исходники не смотрел. Скалу не знаю.
          Ответить
          • Some - скаловый Option
            Full - лифтовый Box
            Ответить
            • Можно пример использования на Скала или пример на Хаскеле?
              Ответить
              • Демо:
                val maybeId = Full(5); // usually we don't know it in advance
                // ...
                val userName = maybeId.map(id => UserRepo.find(id)).map(_.name)
                    .openOrThrowException("No user found");
                Ответить
                • По сути монада мэйБи? Представили Option как контейнер. Идея классная, но почему не добавить эти методы в сам Option?

                  За исключением val (что не суть), очень похоже на Nemerle. Хорошо сделали. Порт скал`ы под .NET, есть?
                  Ответить
                  • >Идея классная, но почему не добавить эти методы в сам Option?
                    Ниже увидел ваше предположение. Глуповато вышло. Чем боролись, на то и напоролись.
                    Ответить
                  • > По сути монада мэйБи?
                    Да.

                    > почему не добавить эти методы в сам Option
                    Всё из демо (кроме openOrThrowException) можно сделать и с обычной Option, она вполне себе функциональна. Просто лифтовцам нужно было много утилит, которые добавить в Option нельзя, манки-патчинг в скале запрещён.
                    http://www.scala-lang.org/api/current/scala/Option.html

                    > Порт скал`ы под .NET, есть
                    Говорят, можно писать на scala прямо в Visual Studio
                    http://www.scala-lang.org/node/10299
                    Ответить
                    • >openOrThrowException
                      Извлечь из монады или кинуть исключение. Это круто вообще. В Немерле такого вроде нет( Да и вообще поддержки обобщения мейби до контенера - тоже вроде нет. (

                      >Просто лифтовцам нужно было много утилит, которые добавить в Option нельзя
                      Это типа тех, что ты показал, например map и так далее?

                      >манки-патчинг в скале запрещён.
                      Методы-расширения как под .NET?
                      Ну да, согласен. В Option для Nemerle можно это добавить и вручную.
                      Ответить
                      • Если сходить по ссылке, можно увидеть map и ещё много всего интересного. А нету как раз openOrThrowException (open особенно хорошо сочетается с Box).
                        Ответить
                        • Кстати, они овер-инженеры. Добавили бы в Option просто ToList. Почти все бы сразу решилось.

                          >Если сходить по ссылке
                          Она не кликается.
                          На самом деле спасибо.
                          Ответить
                          • > Добавили бы в Option просто ToList. Почти все бы сразу решилось.

                            Тогда maybeSmth.toList.map(_.name) вернёт список, а не Option, как должно быть. Плюс лишний объект, минус более простая и быстрая реализация map.
                            Ответить
                            • Это серьезный аргумент. Но таки добавить ToOption тоже можно, хоть и не так красиво уже...
                              Ответить
                              • В Box объявлено неявное преобразование в Option, toOption не нужен
                                Ответить
                                • Вы выпали из контекста.
                                  Антиоверинженеринг:
                                  option1.ToList().ToOption();
                                  И Box почти не нужен.
                                  Ответить
                                  • А если в списке 5 элементов? Нет уж, не нужно юзать Maybe через List.
                                    Ответить
                                    • Очевидно исключение.
                                      Ждем шизофреничного предложения Options<Options<T>>.
                                      Ответить
                                      • Поскольку Option - монада, для неё определена операция join, т.е. преобразование M<M<T>> => M<T>, и смысла в такой записи просто нет. Со списками чуть поинтереснее, иногда нужен именно List<List<T>>.
                                        Ответить
                                        • Очень верное замечание.

                                          >join, т.е. преобразование M<M<T>> => M<T>
                                          Ничего себе как продумано. Полная аналогия со списком. Уважение создателю. Вот что значит системный подход.

                                          >Со списками чуть поинтереснее, иногда нужен именно List<List<T>>.
                                          Ну так и не вызывай join. Какие проблемы?


                                          PS: Пост ниже 154585 я написал несколько раньше этого поста.
                                          Ответить
                                    • Кстати, что Concat над боксами вернет по вашему? Очевидно какой-то энумератор или лист. Так что даже тут сходится. Монада МожетБыть - частный случай Монады лист, очевидно.
                                      Ответить
                                      • > Монада МожетБыть - частный случай Монады лист, очевидно
                                        bool это тоже частный случай int, но с ним же лучше, чем без него
                                        Ответить
                                        • bool и int имеет разную семантику. Это только с точки зреия реализации частный случай. В случае монады семантика очень близка.
                                          Ответить
                      • > Методы-расширения как под .NET?
                        Методы-расширения ещё ладно, хотя мне они не нравятся. Я скорее о возможности напрямую изменить поведение базовых классов, как в Ruby.
                        Ответить
                        • Можно пример? Возможность изменять поведение базовых классов - это виртуальные функции.
                          Ответить
                          • В руби можно заменить любой метод у базового класса (например, метод + у класса целых чисел так, чтобы он выполнял умножение), при этом все числа во всей системе начнут вести себя по-новому.
                            Ответить
                    • Кстати молодцы скаловцы. Вот монады в немерле прикрутили через Computation Expression через метапрограммирование и из-за некоторых ограничений метапрограммирования в Немерле прикрутилось это все не достаточно элегантно. Кстати по этой причине решили сделать Немерле 2.0. Глуповато, ага. Но монады там конечно посильнее. И монада лист, и монада асинхронного программирования и континуации и др и все через один синтаксис.
                      Ответить
                      • В Scala можно выразить typeclasses, т.е. объявить функторы, монады, стрелки и прочий матан и написать общие методы для работы с ними через ViewBounds. А потом прикрутить соответствующее поведение (fmap, bind, etc.) к уже существующим типам через implicit'ы.
                        Плюс и минус такого решения в том, что в любом случае будут использоваться только стандартные механизмы языка, никакого метапрограммирования или особого синтаксиса. Ну, и без хаскеловской лени временами будет не очень круто, хоть и не критично (в Scala вроде можно объявить ленивую инициализацию аргумента функции, т.е. в выражении x(y + 7) часть (y + 7) будет упакована в thunk и вычислена при обращении внутри x).
                        Ответить
                        • Вот конечно скала более системно проработана, чем Немерле...
                          Скала под .нет юзабильна? IDE с авто дополнением кода? Демонстрация выведенных типов по подводу мыши? Ну и может формошепка есть? Ну и под Java тоже самое есть?
                          Ответить
                          • Под .Net не пробовал. В жабе не очень всё хорошо с IDE, т.к. язык очень сложный, и написать IDE для него - проблема. Мне нравится IntelliJ IDEA, к ней есть плагины для Scala и SBT, но они иногда лагают. Есть плагин для eclipse, он вроде ошибки и типы правильно подсвечивает, но тормозит и косячит при рефакторинге. Есть даже сносный плагин для emacs - ensime - с дополнением символов, но его установка и настройка требуют определённых ограничений и усилий.
                            Ответить
                            • > В жабе не очень всё хорошо с IDE, т.к. язык очень сложный
                              Проще язык чем джава - найти сложно. C# и то сложнее. Если уж на то пошло, то одни из самых сложных языков для IDE - Nemerle с его диким выводом типов и диким метапрограммированием или просто дикий С++.
                              При этом в Немерле отличная иде, не уступающая C#. Ну и для С++ найти хорошую IDE не представляет труда, если искать, в том числе и среди плагинов.
                              Ответить
    • Несимметричный оператор равенства? И эти люди смеют ругать C++? Ох!
      Ответить
      • Когда это Дэвид Поллак ругал с++?
        Ответить
        • За Дэвида Поллака не скажу, но есть у нас на работе один адепт Скалки...

          Кстати возможность сломать семантику операторов - один из аргументов Линуса Торвальдса против C++ в ядре.
          Ответить
          • Возможность написать несимметричную проверку на равенство не зависит от языка. Джавистам, кстати, даже чаще вдалбливают про три условия отношения эквивалентности, на всех собеседованиях спрашивают. В Programming in Scala целая глава написана о том, как надо правильно писать equals и hashCode (Chapter 30: Object Equality).

            Почему так реализовали equals в самом часто используемом классе в общем-то неплохого фрэймворка - тайна. Видимо, Поллак был под веществами.
            Ответить
            • >Джавистам, кстати, даже чаще вдалбливают про три условия отношения эквивалентности
              Догадовался, что они есть, но что-за условия, где прочитать?
              Ответить
              • рефлективность, симметрия, транзитивность
                Ответить
                • Это соответственно:
                  a==b => b==a
                  a==b && b==c => a==c
                  Что ещё?
                  Ответить
                  • a==a
                    Ответить
                    • Ты прав... :/
                      Ответить
                      • А аналогичное для операции < ?
                        a < a => ложь
                        a < b && b < c => a < c
                        Где-то ошибся или что-то ещё забыл?
                        Ответить
                        • Да:
                          a < b -/-> b < a (relation is not simmetrical)
                          a < b /\ b < c --> a < c (relation is transitive)
                          a < a --> a < a (vacuously true :), so, reflexive)

                          Нужно еще учитывать, что такие операции определены не для всех множеств (например, деление на множестве натуральных чисел не определено в этом плане).
                          Ответить
                          • PS. Ща понабегут блюстители и скажут, что ноль не натуральное число, ну что вам сказать...
                            Ответить
                          • > a < b -/-> b < a
                            Это что-то из корабельного журнала капитана очевидность?

                            > a < a --> a < a
                            Это я совсем не понял...
                            Ответить
                            • Прикинул, корабельный журнал КО, гы.
                              "Проснулся в 8.00. Было утро."
                              или
                              "Мы плыли по морю. Кругом была вода."
                              Ответить
                            • Математика тем и замечательна, что всегда описывает очевидные вещи. Что в этом удивительного?

                              vacuous truth - такая истинность, которую нельзя опровергнуть, т.как нет возможности найти пример, который бы показывал обратное утверждаемому. Для простоты будем считать, что a - натуральное число, тогда нет такого a, при котором P(a < a) = true, соответственно, доказать, что P(a < a) ~= P(a < a) не получится, т.как нам нужен, по определению, такой предикат P() который дает позитивный результат.
                              Но это, вобщем-то, была шутка...
                              Ответить
                          • наверное таки (a<=b) /\(b<=a) --> a=b
                            а вот a < a --> a < a нету, потому что ко

                            да, в изначальном определении свойства говорились не про > а именно про >=
                            Ответить
            • >Джавистам, кстати, даже чаще вдалбливают про три условия отношения эквивалентности
              Ох бля. В джаве настолько хуёвые нативные equalsы и настолько много хинтов, граблей, правил, и исключений из них - чтобы реализовать правильно equals - это вообще целая наука. Лень даже вдаваться в детали.

              Проблема настолько масштабна, что апачи даже написали специальную фабрику под названием EqualsBuilder.

              Только за один equals жабу можно смело называть говном.
              One does not simply implement correct equals in Java.
              Ответить
          • Собственно, я нашёл автора этих чудесных строк. Когда вы увидите его фотку вопросы отпадут сами собой:
            https://github.com/indrajitr

            А как вам этот кусочек?
            /**
             * Returns true if the value contained in this box is equal to the specified value.
             */
            def ===[B >: A](to: B): Boolean = false
            Ответить
            • c === поторопился: его переопределяют в Full. Но дока смотрится забавно.
              Ответить
            • >Когда вы увидите его фотку вопросы отпадут сами собой
              Ты подарил мне тот редкий момент, когда ожидаемое совпадает с действительным...
              Ответить
    • А зачем вообще этот класс, когда есть Option?
      Ответить
      • В Box гораздо больше методов (в т.ч. утилитных) и неявных преобразований.
        Ответить
        • А почему бы не расширить Option?
          Ответить
          • Может потому, что он sealed (т.е. все подклассы должны находится в том же файле, что и Option)?
            Ответить
      • They see me scriptin', they hatin'.
        Ответить
    • Я плохо умудрен в системе скала типов, но почему
      >foo == boxedFoo //is false
      это скомпилируется? this же имеет тип бокс. А получается, что левая часть разбоксирована.

      >(this, other) match{
      И почему такой странный матчинг?
      match(this, other){
      Ответить
      • > почему это скомпилируется
        В языках с OOP, где есть наследование, нельзя ограничивать тип оператора ==:
        val x: String = "x"
        val y: AnyRef = x
        x == y // must not compile?
        Ответить
    • Ну и моё мнение по вопросу:
      Понятно, что там ещё со ссылками разница какая то есть, но с моим знанием тамошней системы типов, опустим этот момент.
      Full x == Full y => x == y
      Full == Empty => false
      Empty == Full => false
      Empty == Empty => false
      Ответить
      • Дополню:
        Full x == y => x == y
        x == Full y => x == y //Здесь моё мнение с авторским почему то не совпадает. Или я не прав?
        x == Empty => false
        Empty == x => false
        Ответить
        • (Full(x), Full(y)) => x == y
          (x, y) => x eq y
          Ответить
          • Что это? Это ваш правильный вариант?
            Знаю, что в жабе == сравнивает по адресу ссылки, а equals сравнивает по значению. Выше я писал безотносительно этого.
            А уж что здесь eq значит - не знаю.
            Ответить
            • В Scala == - это null-safe equals, а eq - сравнение по адресу
              Ответить
              • null-safe equals ведет себя также как описано в моих постах?
                http://govnokod.ru/11813#comment154573
                Только обозначения чуть сменим:
                Empty эквивалентно null
                Full эквивалентно конкретному не нулевому значению.
                Ответить
                • Только естественно вместо '==' вызовется перегруженный equals
                  Ответить
                • Что-то вроде этого (java):
                  public static boolean equal(@Nullable Object a, @Nullable Object b) {
                      return a == b || (a != null && a.equals(b));
                  }
                  (Empty, Empty) => true, все пустые коробки равны, иначе рефлексивность нарушена.
                  Ответить
                  • >(Empty, Empty) => true, все пустые коробки равны, иначе рефлексивность нарушена
                    Я не согласен. Не монадично это.
                    Ты не коробки сравнивать должен, а элементы, что лежат в коробке.
                    Для начала воспользуемся многолетним опытом исследователей из других областей.
                    Если мне не изменяет память (поправьте меня если я ошибусь) взгляним на NAN (Not a number) в FPU и null в SQL.
                    Если x - любое, то
                    1)x == NAN => false
                    NAN == x => false
                    NAN == NAN => false
                    зато isNAN(x) вернет всеж интересующий ответ на вопрос.
                    2)null ведет себя аналогично в SQL запросах.
                    x == null => false
                    null == x => false
                    null == null => false
                    Если ты боишься, что у тебя будут проблемы с поиском из-за нарушения рефлексии, то это не так.
                    Монада, например, хранит или объект\объекты или провал прошлого вычисления.
                    map1.find(Empty) должа вернуть Empty, а не найти закинутое каким-то идиотом по ключу Empty некое значение Full ("kokoko") например (если это ассоциативный массив).
                    Аналогично если расширять операции, то:
                    Empty*x = Empty
                    Также как и
                    NAN*х = NAN. Если сменить настройки FPU, то понятно, что нам выкинут исключение и по сути все нижележащие вычисления не обработаются, что посути тот же NAN (Empty), протащенный через всю цепочку вычислений до точки обработки в монадах.
                    Ответить
                    • *до точки обработки исключения, как в монадах.
                      Ответить
                    • > Ты не коробки сравнивать должен, а элементы, что лежат в коробке
                      В методе equals класса Box нужно сравнивать именно коробки.
                      Ответить
                      • Что в коробке, то и на коробке.
                        http://www.youtube.com/watch?v=3R9K_7xuFLQ
                        Ответить
                      • > В методе equals класса Box нужно сравнивать именно коробки.
                        Где аргументы? Не нужно прикрываться бумажкой мол вот стандарт и мы ему бездумно следуем. Запомните, в ресерчевых областях это не работает.
                        Ответить
                        • Кстати, раз так волнуетесь за рефлексивность, то будем считать, что каждая пустота уникальна, как и мифическая переменная World в хаскеле.
                          Так что совершенно логично, то одна пустота не равна другой.
                          Ответить
                  • >return a == b || (a != null && a.equals(b));
                    http://old.i-business.ru/wp-content/gallery/hoare2507/img_7506.jpg
                    Этот код расстраивает Хоара.
                    Ответить
    • Кстати, а в Scala есть реальные монады, как в Xаскеле или Nemerle?
      Ответить
      • Что ты понимаешь под "Реальными" монадами? Я тебе могу на жабе либу монадическую написать, только вот из-за унылого жаба-синтаксиса клиентский код громоздким будет. Если интересны функциональные возможности скалы, вот годный проект:
        http://code.google.com/p/scalaz/
        Ответить
        • Реальные монады (см. Хаскель и Немерле), это когда можно посредством одного монадического синтаксиса реализовывать и использовать множество видов монад, скрытых под синтаксическим сахаром. То есть один синтаксис для всех видов: cont, async, maybe, mlist и прочее прочее прочее.
          Ответить
          • Тогда да, в Scala можно реализовать такие монады.
            Ответить
            • Это будут открытые bind, apply и прочее? Это не то. Синтаксического сахара не хватает. В шарпе тоже так можно, но писать очень громоздко и не красиво.
              Ответить
              • По поводу синтаксического сахара: в Scala есть конструкция for, которая на самом деле совсем не цикл. Она очень похожа хаскелевскую do-нотацию: преобразует сахарные конструкции в код, содержащий map, flatMap и filter. Трансформация работает на уровне AST, т.е. достаточно просто объявить эти методы в своём классе, чтобы для него стал работать for-сахар. Поскольку flatMap это и есть bind, налицо сахарок для работы с монадами (вместо return используется apply).
                Ответить
                • А можно ссылочку на пример или описание?
                  Что-то типа как в F# полагаю?
                  http://msdn.microsoft.com/en-us/library/dd233182.aspx
                  Одна из реализаций этих методов seq:
                  http://msdn.microsoft.com/en-us/library/dd233209.aspx
                  или query:
                  http://msdn.microsoft.com/en-us/library/hh225374.aspx
                  Но по дефолту каких либо других монад реализованных нет.
                  В немерле похожим образом, только конструкция монадического сахара введена через метапрограммирование, немного пошире и по дефолту реализованы многие монады.
                  Ответить
                  • Скачай уже себе Programming in Scala, читается легко и приятно, толстая только, зараза. Про сахар for - Chapter 23: For Expressions Revisited.
                    Там нет никакого полиморфизма, по for тупо генерится код с map, flatMap и filter, а уж потом проходит проверка типов. Определи в своей монаде эти методы, и можешь смело юзать for.
                    Ответить
        • >KleisliArrow
          >CokleisliArrow
          Это те стрелки, что в хаскеле выглядят в виде операций? По моему, сам будешь не рад, если ими будешь пользоваться...
          Ответить
        • > List(1, 2, 3).replicateM
          > List(1, 2).foldRightM
          Вот ты на хаскель наезжал, что мол много функций с префиксом м специально для монад, а тут таже самая проблема
          Ответить
          • Дык проблема в самих монадах, а не в языке
            Ответить
            • Если разрабатывать монадафрендли язык, то проблемы в монадах не будет. Это как спроектируешь его. Вот в Немерле нет особых функций для монад. И так все работает. Реализация на уровне метапрограммирования сама разруливает все проблемы.
              Ответить
        • Впрочем в любом случае молодцы. Спасибо.
          Ответить

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