На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела:
1. Название темы - краткое описание кто/что против кого/чего
2. В первом сообщении - список параметров, по которым идет сравнение.
3. Старайтесь аргументировать свои высказывания. Фразы типа "Венда/Слюникс - ацтой" считаются флудом.
4. Давайте жить дружно и не доводить обсуждение до маразма и личных оскорблений.
Модераторы: Модераторы, Комодераторы
Страницы: (33) « Первая ... 7 8 [9] 10 11 ...  32 33  ( Перейти к последнему сообщению )  
> trait + impl vs class , навеяно Rust'ом
    Цитата applegame @
    функции описанные в треатах - виртуальные и абстрактные
    Немного не так. Функции будут виртуальными или нет в зависимости от использования. Если через "трейт-обьект", то да, виртуальные. Если через дженерик - нет. В С++/D мы должны заранее выбирать "каким видом полиморфизма воспользоваться".

    Ну и функции в трейтах вполне могут иметь реализацию, просто она не может зависить от данных.

    Цитата applegame @
    отсутствие private/protected/public
    Приват/паблик вполне есть, хотя и немного другие. Не уверен, что отсутствие protected - недостаток, особенно при отсутствии наследования (данных).

    Цитата applegame @
    Написать шаблон аналогичный дженерику ничуть не сложнее.
    Я бы сказал, что всё-таки сложнее. Опять же, главная "проблема", в том, что в С++ нет для этого "инфраструктуры", а в расте - есть.

    Цитата applegame @
    И уж тем более я не буду городить оберток без крайней необходимости.
    Обёртки, если мы именно про отдельные рантаймовые сущности и в расте "без нужны" не городятся.

    Обычный способ работы с трейтами - это как раз через дженерики. Просто так передавать указатели/ссылки на трейт-объекты особого смысла нет, нужно оно если мы хотим вещей типа "сохранить в массиве разные объекты с общим интерфейсом" - тут и в С++ будут тоже указатели. Или если нам надо что-то типа std::function.

    Цитата applegame @
    Такие декораторы не часто нужены в реальной жизни
    Задача ведь не "сделать декоратор", а реализовать интерфейс для существующего типа. В С++/Д, если мы не можем использовать шаблоны, то декораторы всё-таки придётся городить.

    Ну а вообще это просто разные подходы. В плюсовом/дшном ООП ты сделаешь интерфейс и предложишь клиентам твоей либы от него наследоваться и передавать тебе указатель. В расте ты обьявишь трейт и клиенты точно так же реализуют его для своих типов.

    Добавлено
    Цитата D_KEY @
    И вообще, см. подпись :)
    :)

    Цитата applegame @
    Но ЕМНИП это implementation defined. Стандарт C++ разве требует чтобы потомок имел тот же размер, что и предок, в случаях когда не добавляются дополнительные данные?
    Кстати, да. "Empty base optimization" - это только возможная, но не обязательная оптимизация.

    И всё-таки я вернусь к тому, что в расте пустые типы занимают 0. Вроде, даже в относительно новых языках, размер будет 1. Интересно, тут есть какие-то преимущества/недостатки? Или разница настолько несущественна, что всем пофиг?
      Цитата D_KEY @
      Нет. Есть возможность для trait'а указать, что его реализация типом требует так же реализации других трейтов.
      Не понял. trait'ы вроде наследуются, нет?
      Цитата D_KEY @
      Допустим(а интерфейсы в D могут иметь реализацию методов по умолчанию?), но кроме них-то нет ничего. Никаких абстрактных классов, например.
      В D интерфейсы не могут иметь реализацию методов по умолчанию. Абстрактные классы есть, но ты ими можешь не пользоваться и даже не знать об их существовании.
      Цитата D_KEY @
      Виртуальные или абстрактные. Да. Но это не нужно указывать, об этом не нужно думать, как о каком-то отдельном механизме. Просто trait.
      В D тоже ничего не нужно указывать, по умолчанию все виртуальное, а в интерфейсах еще и абстрактное. Можно не думать и даже не знать, что бывают еще и невиртуальные и неабстрактные функции.
      Цитата D_KEY @
      Не теряй контекст, мы о простоте.
      D позволяет простое писать просто, а сложное сложно.
      Цитата D_KEY @
      Нет. Дженерики - это параметрический полиморфизм, который, в общем случае, шаблонами не покрывается.
      И в случае Rust?
      Цитата D_KEY @
      Помнишь пример с контролем равенства размера двух списков/векторов во время компиляции?
      Нет, не помню. напомни пожалуйста или дай ссылку.
      Цитата D_KEY @
      Если ты вводишь в язык перегрузку, полноценные шаблоны и специализации, то правила уже простыми не будут.
      Все эти правила необязательны к использованию. Если они тебе кажутся сложными или избыточными - просто не используй их.
      Цитата D_KEY @
      Так в Rust вообще нет сложных концепций. Тут скорее ты должен привести пример, когда нам нужно все это многообразие средств и их мощность.
      Я плохо знаю rust, поэтому мне трудно приводить примеры. Что-нибудь не сильно навороченное, может сериализация?
      ExpandedWrap disabled
        // если компилируется код data.serialize(serializer);
        void serialize(S,T)(ref S serializer, T data) if(isCustomSerializable!T) {..}
        // структуры и классы
        void serialize(S,T)(ref S serializer, T data) if(isAggregate!T) {..}
        // Скаляры
        void serialize(S,T)(ref S serializer, T data) if(isScalar!T) {..}
        // Массивы
        void serialize(S,T)(ref S serializer, T data) if(isArray!T) {..}
        Цитата DarkEld3r @
        Ну я специально про С++ уточнил - там ведь со строками в шаблонах нормально работать нельзя. А можно простой пример шаблона в D, который со строкой работает?

        Для того чтобы что-то собралось в compile-time не обязательно, чтобы это был шаблон. Любую функцию можно выполнить, если она не завязана на внешние данные. В C++ уже тоже есть constexpr, но пока сильно урезанный по сравнению с D. Шаблоны с строковыми параметрами активно применяются в перезагрузке операторов. Например opDispatch для перезагрузки обращения к несуществующему полю, в качестве параметра использует название метода:

        ExpandedWrap disabled
          import std.stdio;
           
          struct Foo {
              void opDispatch(string method, ARGS...)(ARGS args) {
                  writefln(`method "%s" with %s parameters`, method, ARGS.length);    
              }
          }
           
          void main() {
              Foo foo;
              foo.bar("test");
              foo.baz(1, "test");
          }

        ExpandedWrap disabled
          method "bar" with 1 parameters
          method "baz" with 2 parameters
          Цитата applegame @
          Не понял. trait'ы вроде наследуются, нет?

          Ну там такое "наследование", которое просто требует от типа, который реализует трейт, реализовать еще и всех trait'ов-"предков".

          Цитата
          В D интерфейсы не могут иметь реализацию методов по умолчанию.

          trait в Rust могут.

          Цитата
          Абстрактные классы есть, но ты ими можешь не пользоваться и даже не знать об их существовании.

          Цитата
          В D тоже ничего не нужно указывать, по умолчанию все виртуальное, а в интерфейсах еще и абстрактное. Можно не думать и даже не знать, что бывают еще и невиртуальные и неабстрактные функции.

          Ну не верю :) Наверняка в коде это все часто и активно используется. А значит, программист должен это знать.

          Цитата
          Цитата D_KEY @
          Нет. Дженерики - это параметрический полиморфизм, который, в общем случае, шаблонами не покрывается.
          И в случае Rust?

          Думаю, что да. Но мне не хватает экспериментов с ним, а я пока не хочу тратить на это время.

          Цитата
          Нет, не помню. напомни пожалуйста или дай ссылку.

          у нас в холиварах
          ЛОР
          ЖЖ

          Цитата
          Все эти правила необязательны к использованию. Если они тебе кажутся сложными или избыточными - просто не используй их.

          Как мне разбираться в чужом коде?

          Цитата
          ExpandedWrap disabled
            // если компилируется код data.serialize(serializer);
            void serialize(S,T)(ref S serializer, T data) if(isCustomSerializable!T) {..}
            // структуры и классы
            void serialize(S,T)(ref S serializer, T data) if(isAggregate!T) {..}
            // Скаляры
            void serialize(S,T)(ref S serializer, T data) if(isScalar!T) {..}
            // Массивы
            void serialize(S,T)(ref S serializer, T data) if(isArray!T) {..}

          Как я понимаю, просто создается trait сериализуемых объектов(возможно с какой-то реализацией по умолчанию). Далее он специализируется для других трейтов, потом уже специализируется для каких-то конкретных типов, если нужно. Разве этого недостаточно? Хотя могу ошибаться, тут лучше пусть DarkEld3r расскажет.
          Сообщение отредактировано: D_KEY -
            Цитата DarkEld3r @
            Кстати, поигрался немного с трейтами в D - в ideone если одна из требуемых функций имеет неподходящую сигнатуру, то компилятор не очень понятно ругается:
            template prog.test(Range) if (isInputRange!(Range)) does not match any function template declaration
            То есть не показывает, что именно не подходит. Это там компилятор такой или везде так?
            Это задуманная фича, перекочевала в D из C++. Называется SFINAE. То бишь если шаблон не подходит, или инстанцирцется с ошибкой, то компилятор просто его пропускает и идет дальше. Вдруг ниже по коду будет подходящая специализация. При желании можно самому выводить вменяемые ошибки, но это как-то не принято:
            ExpandedWrap disabled
              import std.traits;
              import std.range;
                  
              struct Test
              {
                bool empty() { return true; }
                int popFront() { return 10; }
                int front(int) { return 10; }
              }
                  
              auto test(Range)(Range r) {
                static assert(isInputRange!Range, "type '" ~ Range.stringof ~ "' must be an InputRange");
              }
                  
              void main() {
                Test t;
                test(t);
              }

            ExpandedWrap disabled
              prog.d(12): Error: static assert  "type 'Test' must be an InputRange"
              prog.d(17):        instantiated from here: test!(Test)
              Цитата applegame @
              Не понял. trait'ы вроде наследуются, нет?
              Они-то "наследуются", но для типа в итоге всё равно надо реализовывать два отдельных трейта. Просто если ты реализуешь только тот, что наследуется от базового, то компилятор на это укажет.

              То есть не так как в "обычном ООП" - отнаследовался от пачки интерфейсов и потом реализовал их внутри одного калсса.

              Цитата applegame @
              Что-нибудь не сильно навороченное, может сериализация?
              В расте будет соответствующий трейт, который надо будет реализовать для нужных типов. Вернее, он даже был в стандартной библиотеке, потом убрали и предлагают пользоваться сторонней библиотекой (их даже несколько есть). Хз почему, я особо не копал. Может решили, что универсальная реализация не всех устроит, а может стабилизировать не успели.

              Цитата applegame @
              Для того чтобы что-то собралось в compile-time не обязательно, чтобы это был шаблон.
              Да, точно. Но на плюсовых constexpr нормально компиляцию регекспов точно не сделаешь. Ну а в D, действительно, проблем с этим быть не должно.

              Кстати, как в D затребовать/гарантировать выполнения функции именно на этапе компиляции?

              Добавлено
              Цитата D_KEY @

              И не дает переопределять дефолтные методы родительских трейтов.
              Даёт. :)
                Цитата DarkEld3r @
                Цитата D_KEY @

                И не дает переопределять дефолтные методы родительских трейтов.
                Даёт. :)

                А можно пример, как это работает? И в каком месте мне для своего типа менять реализацию, при реализации trait'а родителя или при реализации trait'а потомка? Что будет использоваться, моя реализация trait'а родителя или дефолтная реализация trait'а потомка, если мы работаем с объектом через trait потомка?

                Добавлено
                Цитата D_KEY @
                Цитата
                Нет, не помню. напомни пожалуйста или дай ссылку.

                у нас в холиварах
                ЛОР
                ЖЖ

                Цитата D_KEY @
                Собственно, С++ шаблоны напрямую не работают как раз потому, что они не являются (полиморфными) типами - они именно шаблоны, по которым генерируются конкретные не параметризованные типы.

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

                  Про SFINAE в курсе, но по идее, компилятор мог бы выдавать нормальную диагностику, если функция ровно одна. Но вообще это как раз пример "проблем" с шаблонами, которых в расте просто не может быть.
                    Цитата D_KEY @
                    А можно пример, как это работает?
                    Был не прав - не работает оно. Если попытаться переопределить в трейте "наследнике" базовый метод, то получится просто новый метод. И если реализовать для типа оба трейта, то при вызове этого метода будет ошибка компиляции - "multiple applicable items in scope". Можно неоднозначность руками разруливать.
                    ExpandedWrap disabled
                      trait Base {
                          fn foo(&self) { println!("Base::foo") }
                      }
                       
                      trait Derived : Base {
                          fn foo(&self) { println!("Derived::foo") }
                          
                          fn bar(&self) { println!("Derived::bar") }
                      }
                       
                      struct Test;
                       
                      impl Base for Test {}
                      impl Derived for Test {}
                       
                      fn main() {
                          let a = Test;
                          
                          //a.foo(); // multiple applicable items in scope
                          a.bar();
                          
                          Base::foo(&a);
                          Derived::foo(&a);
                      }
                      Цитата DarkEld3r @
                      В расте будет соответствующий трейт, который надо будет реализовать для нужных типов.
                      И функция сериализации будет в качестве аргумента принимать этот трейт? Дело попахивает динамическим полиморфизмом. Не очень похоже на "проще и эффективнее". Скорее наоборот.
                      Цитата DarkEld3r @
                      Про SFINAE в курсе, но по идее, компилятор мог бы выдавать нормальную диагностику, если функция ровно одна. Но вообще это как раз пример "проблем" с шаблонами, которых в расте просто не может быть.
                      Звучит как "это как раз пример проблем со здоровьем, которых у трупов не может быть". Конечно же в расте не может быть проблем с шаблонами, потому что и там нет :). На самом деле это проблема компилятора, а не самого языка.
                      Сообщение отредактировано: applegame -
                        Цитата DarkEld3r @
                        Кстати, ещё один вопрос - в С++ ведь нельзя шаблонным параметрам-функциям нормально ограничить сигнатуру.

                        Ага, тем, у которых всё никак не увеличивается размер, запретили SFINAE.
                          Цитата DarkEld3r @
                          Кстати, как в D затребовать/гарантировать выполнения функции именно на этапе компиляции?

                          По всякому. Например так:
                          ExpandedWrap disabled
                            enum result = foo();
                          Сообщение отредактировано: applegame -
                            Цитата D_KEY @
                            Помнишь пример с контролем равенства размера двух списков/векторов во время компиляции?

                            Там опять же всё решается затиранием типа для имитации generic.
                              Цитата applegame @
                              И функция сериализации будет в качестве аргумента принимать этот трейт? Дело попахивает динамическим полиморфизмом.
                              Я уже не знаю в какой раз повторяю, что в расте, в большинстве случаев, с трейтами принято работать через дженерики. То есть будет как-то так:
                              ExpandedWrap disabled
                                fn foo<T: Serializable>(data: &T) { ... }
                              И никакого динамического полиморфизма.

                              Цитата applegame @
                              Звучит как "это как раз пример проблем со здоровьем, которых у трупов не может быть".
                              Ну зачем же передёргивать? Я нигде не утверждал, что дженерики и шаблоны одно и то же. Но такие решения, при создании языка, вполне могли приниматься исходя из желания сделать более точные сообщения об ошибках.

                              Цитата applegame @
                              На самом деле это проблема компилятора, а не самого языка.
                              Так-то да, но язык существует не в вакууме. ideone предлагает два варианта компилятора D, проверил на обоих. Потому и спросил - их ведь больше, да и версии там непонятно какие, может это давно решено.

                              Цитата applegame @
                              По всякому. Например так:
                              Ну про enum (очень поверхностно) в курсе. Значением ведь может быть любой тип?
                              Ну и раз, "по разному", то может ещё пару вариантов приведёшь? A то бегло не нагуглить не удалось.

                              Цитата MyNameIsIgor @
                              Ага, тем, у которых всё никак не увеличивается размер, запретили SFINAE.
                              Покажи кодом.
                              Ну и меня интересовало есть ли в D что-то на эту тему.
                                Цитата DarkEld3r @
                                Покажи кодом.

                                Так ведь
                                Цитата DarkEld3r @
                                Про SFINAE в курсе
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (33) « Первая ... 7 8 [9] 10 11 ...  32 33


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0876 ]   [ 15 queries used ]   [ Generated: 18.07.25, 17:46 GMT ]