На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
Дорогие друзья! Поздравляем вас с днём Победы!
msm.ru
! Правила раздела:
1. Название темы - краткое описание кто/что против кого/чего
2. В первом сообщении - список параметров, по которым идет сравнение.
3. Старайтесь аргументировать свои высказывания. Фразы типа "Венда/Слюникс - ацтой" считаются флудом.
4. Давайте жить дружно и не доводить обсуждение до маразма и личных оскорблений.
Модераторы: Модераторы, Комодераторы
Страницы: (16) « Первая ... 10 11 [12] 13 14 ... Последняя » все  ( Перейти к последнему сообщению )  
> Rust vs C++ , очередная шляпа
    Цитата Qraizer @
    Сиречь придумали универсальный протокол, придерживаться которого должны обе стороны.Ага?
    Более-менее придумали.
      Цитата korvin @
      Давай пример кодом: как было до рефакторинга, как стало и что не так, а то я что-то не могу понять, на что ты жалуешься.

      Ну вот был такой класс:
      ExpandedWrap disabled
        class A
        {
        public:
            virtual ~A() = default;
            virtual std::string foo() const
            {
                return "A";
            }
        };


      И тест
      ExpandedWrap disabled
        void testA()
        {
            A a;
            assert(a.foo() == "A");
        }


      И вот какой-то из наследников:
      ExpandedWrap disabled
        class B: public A
        {
        public:
            virtual std::string foo() const
            {
                return "B";
            }
        };


      И его тест
      ExpandedWrap disabled
        void testB()
        {
            B b;
            assert(b.foo() == "B");
        }


      В реальном коде используем как-то так:
      ExpandedWrap disabled
            auto ptr= factory->make_instance(...);
        ...
            std::cout << ptr->foo() << std::endl;


      Все ок, если создадим экземпляр B, то будет выведено "B".

      Теперь рефакторили и заменили сигнатуру:
      ExpandedWrap disabled
        class A
        {
        public:
            virtual ~A() = default;
            virtual std::string foo(int x) const
            {
                return "A";
            }
        };


      Подправили тесты:
      ExpandedWrap disabled
        void testA()
        {
            A a;
            assert(a.foo(10) == "A");
        }


      Подправили использование:
      ExpandedWrap disabled
            auto ptr= factory->make_instance(...);
        ...
            std::cout << ptr->foo(10) << std::endl;


      Подправили тех наследников, о которых помнили.
      А вот про B забыли.

      В результате, теперь в случае экземпляра B, выводиться будет A.

      И, внезапно, если бы там был override, то компилятор бы ругался и никакой проблемы бы не возникло.

      Добавлено
      Цитата korvin @
      Зачем это всё? Чтобы лучше всё структурировать вместо каши из override и non-override методов, чтобы IDE лучше понимала семантику кода, в частности выполняла семантически более точный рефакторинг при изменении сигнатуры методов «родителей», который мы тут обсуждали. + один набор юнит-тестов на разные реализации. И при этом добавить некоторую гибкость в виде протоколов.

      Я правильно понимаю, что это все потребует нового языка? :D

      Цитата
      Хз как там в ваших D/Rust/C#, но без аналога Go'шных интерфейсов или OCaml'овских object type'ов в Java грустновато.

      Вот тут не понял. Зачем тебе goшные интерфейсый в java?

      Цитата

      Но это только интерфейсы, осталось разобрать наследование реализаций (классов)…

      Это будет ближе к практике?

      Добавлено
      Цитата D_KEY @
      И, внезапно, если бы там был override, то компилятор бы ругался и никакой проблемы бы не возникло.

      Изначальный пример http://ideone.com/cac3Ss
      После рефакторинга http://ideone.com/kuCrur
      Если бы был override http://ideone.com/SieIBM

      Цитата
      error: ‘std::__cxx11::string B::foo() const’ marked ‘override’, but does not override
      std::string foo() const override
      Сообщение отредактировано: D_KEY -
        Цитата D_KEY @
        И тест

        Цитата D_KEY @
        И его тест

        Цитата D_KEY @
        Все ок, если создадим экземпляр B, то будет выведено "B".

        В твоем примере слово virtual абсолютно бессмысленно. Создай подобие интерфейса и перепиши свой код вот так:
        ExpandedWrap disabled
          struct Base
          {
             virtual string foo() const = 0;
             virtual ~Base() = 0;
          };

        ExpandedWrap disabled
          class A : public Base
          {
          public:
              virtual ~A() = default;
              virtual std::string foo() const
              {
                  return "A";
              }
          };

        Потом перепиши тесты:

        ExpandedWrap disabled
          void testA()
          {
              std::uniqe_ptr<Base> pA = std::make_uniqe<A>();
              assert(pA->foo(10) == "A");
          }

        А вот после этого меняй сигнатуру. Тогда будет правильно.

        Добавлено
        Ну или хотя бы в тесте testB сделай динамическое создание класса B, присвоей его переменной базового класса А. У тебя ведь А базовый, присутствуют виртуальные функции. Соответственно ты будешь работать с базовым классом, а не напрямую с B/A.
        Сообщение отредактировано: Wound -
          Цитата Wound @
          В твоем примере слово virtual абсолютно бессмысленно.

          Ты о чем-то своем. Мы обсуждаем пользу override при рефакторинге. При чем тут интерфейсы?

          Добавлено
          Цитата Wound @
          присвоей его переменной базового класса А.

          И часто ты в тестах такой каст делаешь?
            Цитата D_KEY @
            Ты о чем-то своем. Мы обсуждаем пользу override при рефакторинге. При чем тут интерфейсы?

            Ну речь то зашла изначально про интефрейсы.

            Цитата D_KEY @
            И часто ты в тестах такой каст делаешь?

            Какой такой каст делаю? Это обычный дин. полиморфизм называется. У тебя в твоем примере тесты отличаются от реальной работы классов. Т.е. тесты живут своей жизнью, программа живет своей жизнью. Не совсем понятно что ты тестишь. Посмотри на свои функции тестирования, и посмотри на использование:

            Цитата D_KEY @
               
            ExpandedWrap disabled
              auto ptr= factory->make_instance(...);
              ...
                  std::cout << ptr->foo(10) << std::endl;

            Я не вижу использования классов A/B, зато я вижу нечто базовое, через которое может вызваться в зависимости от типа тот или другой метод.
            Раз ты у себя в коде пишешь:
            ExpandedWrap disabled
              auto ptr= factory->make_instance(...);

            Значит это же у тебя должно быть и в тестах. Либо на крайняк, если ты не хочешь тестировать фабрику, должно быть так, как я написал выше, а именно работа через базовый класс.
            Сообщение отредактировано: Wound -
              Цитата Wound @
              Ну речь то зашла изначально про интефрейсы.

              Это обсуждение уже давно откололось от того :)

              Цитата
              У тебя в твоем примере тесты отличаются от реальной работы классов. Т.е. тесты живут своей жизнью, программа живет своей жизнью. Не совсем понятно что ты тестишь.

              Работу класса я тестирую.

              Цитата

              Раз ты у себя в коде пишешь:
              ExpandedWrap disabled
                auto ptr= factory->make_instance(...);

              Значит это же у тебя должно быть и в тестах

              Это уже будет не юнит-тестирование.
              Сообщение отредактировано: D_KEY -
                Цитата D_KEY @
                Это уже будет не юнит-тестирование.

                А что это будет?

                Цитата D_KEY @
                Работу класса я тестирую.

                В таком случае у тебя нет ошибки. И поведение абсолютно предсказуемое. К чему претензия? :D

                Добавлено
                D_KEY, вот представь я пишу все тоже самое, но у меня B не наследуется от А, ну просто два разных класса, с одинаковым методом. А потом вдруг кто то подумает и решит короче, B унаследовать от А, и заодно изменит вот как ты сигнатуру у А. Ну и все далее как у тебя. Что в этом случае не так? Тесты плохие? Или что?
                  Цитата Wound @
                  D_KEY, вот представь я пишу все тоже самое, но у меня B не наследуется от А, ну просто два разных класса, с одинаковым методом. А потом вдруг кто то подумает и решит короче, B унаследовать от А, и заодно изменит вот как ты сигнатуру у А. Ну и все далее как у тебя. Что в этом случае не так? Тесты плохие? Или что?

                  Просто странный код будет :D
                  Я не понимаю, о чем ты сейчас. Мы говорим о пользе override. Я просто привел пример, когда он поможет. И все.
                    Цитата D_KEY @
                    Просто странный код будет
                    Я не понимаю, о чем ты сейчас. Мы говорим о пользе override. Я просто привел пример, когда он поможет. И все.

                    Так ты прочитай что тебе написали в этом посте: Rust vs C++ (сообщение #3808312)
                    И потом посмотри что ты ответил.
                    Тебе говорят, что override нафиг не нужен, например в той же Java, потому что надо писать вот так то и так то, вот об этом написано:
                    Цитата korvin @
                    Зачем это всё? Чтобы лучше всё структурировать вместо каши из override и non-override методов, чтобы IDE лучше понимала семантику кода, в частности выполняла семантически более точный рефакторинг при изменении сигнатуры методов «родителей», который мы тут обсуждали. + один набор юнит-тестов на разные реализации. И при этом добавить некоторую гибкость в виде протоколов. Хз как там в ваших D/Rust/C#, но без аналога Go'шных интерфейсов или OCaml'овских object type'ов в Java грустновато.

                    А ты в ответ пишешь, что он будет делать, если забудет гдето там написать override.
                    override - синтаксический сахар по сути, который просто лишний раз может тебе сказать что у тебя не совпадают сигнатуры базового и производного методов. Но использование его, еще не означает что ты проектируешь систему правильно. И раз у тебя возникают такие ошибки, и тебе помог override, значит скорее всего будут и другие ошибки, на которые синтаксического сахара не найдется.
                    Ну это как скажем assert что ли. То что он есть, еще не спасает тебя от ошибок.
                      Цитата Wound @
                      может тебе сказать что у тебя не совпадают сигнатуры базового и производного методов.

                      Так и я про то.

                      Цитата
                      Но использование его, еще не означает что ты проектируешь систему правильно.

                      А кто говорит о проектировании систем?

                      Цитата
                      И раз у тебя возникают такие ошибки, и тебе помог override, значит скорее всего будут и другие ошибки, на которые синтаксического сахара не найдется.

                      Например?

                      Добавлено
                      Цитата Wound @
                      потому что надо писать вот так то и так то

                      Это уже совсем из другой области вопрос.
                        Цитата D_KEY @
                        Например?

                        Например что у тебя factory->make_instance(...); будет работать не так, как ты ожидаешь.

                        Добавлено
                        Цитата D_KEY @
                        Это уже совсем из другой области вопрос.

                        Ну не знаю, просто у вас тогда странный разговор получается. Тебе объясняют почему в принципе не нужен override, а ты объясняешь от чего он спасает. Так если не писать так, как ты показал - то нафиг этот override нужен то? :D
                          А причём тут вообще проектирование? override ему ортогонален совершенно.
                            Между прочим в С++ override появился сравнительно недавно. И до него как то не особо припомню вот таких вот проблем. Обычно все разруливалось ЮТ.

                            Добавлено
                            Цитата OpenGL @
                            А причём тут вообще проектирование? override ему ортогонален совершенно.

                            Ну как выяснилось у некоторых не ортогонален.
                              Цитата Wound @
                              Цитата D_KEY @
                              Например?

                              Например что у тебя factory->make_instance(...); будет работать не так, как ты ожидаешь.

                              С чего вдруг?

                              Цитата
                              Тебе объясняют почему в принципе не нужен override, а ты объясняешь от чего он спасает. Так если не писать так, как ты показал - то нафиг этот override нужен то? :D

                              Потому что это всего-лишь пример. Иллюстрация.
                              Ты не всегда сможешь отследить изменение сигнатуры в реальном проекте.

                              Добавлено
                              Цитата Wound @
                              Между прочим в С++ override появился сравнительно недавно. И до него как то не особо припомню вот таких вот проблем.

                              А для чего добавили, на твой взгляд?

                              Цитата
                              Обычно все разруливалось ЮТ.

                              Во-первых, ЮТ не являются частью языка. Во-вторых, я мало видел тестов, где бы кастили к базовому классу. Возможно, все кастят, а мне попадалось говно. Но это ничего на самом деле не меняет.
                                Цитата D_KEY @
                                С чего вдруг?

                                Да просто так, оно ж у тебя в тестах не тестируется. Мало ли там что пойдет не так, вместо класса A, создастся класс B например или наоборот.

                                Цитата D_KEY @
                                Потому что это всего-лишь пример. Иллюстрация.
                                Ты не всегда сможешь отследить изменение сигнатуры в реальном проекте.

                                А раньше как отслеживал? :D

                                Цитата D_KEY @
                                А для чего добавили, на твой взгляд?

                                А они как бы все в язык несут, все новомодности модные собирают со всех языков и несут в язык. Чтоб было. :D
                                Ну как синтаксический сахар конечно пойдет. Я ж не против override'ов.

                                Цитата D_KEY @
                                Во-первых, ЮТ не являются частью языка. Во-вторых, я мало видел тестов, где бы кастили к базовому классу. Возможно, все кастят, а мне попадалось говно. Но это ничего на самом деле не меняет.

                                Незнаю, мне напротив попадалось другое. Пишешь ЮТ - которые эмулируют работу, с помощью тех же mock объектов. Как правило помимо самих функций - тестируется еще и функционал который они делают. Потому как в 99% случаев, бывает такое, что для того, что бы юзнуть функцию в ЮТ, для нее нужно настроить окружение. А это подразумевает имитирование работы части функционала.
                                Например там функция ждет от тебя какой нибудь коннектор, провайдер, поток с данными и т.д. чтоб дальше с ним работать, или например еще что то, и а те в свою очередь, для того чтоб вернули ожидаемые значения могут еще что то принимать, что в свою очередь может принимать еще другое. И в итоге ты начинаешь делать mock объекты и эмулировать работу программы в ЮТ. Где практически все косяки, в том числе и те, которые ты написал зачастую всплывают.
                                1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0712 ]   [ 14 queries used ]   [ Generated: 13.05.24, 15:48 GMT ]