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

    Коротко о trait'ах, impl'ах и данных на примере Rust.
    Вместо "классического" ОО подхода, Rust предоставляет отдельные ортогональные механизмы.
    Если классы у нас описывают и методы и данные, то в Rust мы задаем отдельно данные:
    ExpandedWrap disabled
      struct Circle {
          x: f64,
          y: f64,
          radius: f64,
      }


    и отдельно наборы методов:

    ExpandedWrap disabled
      impl Circle {
          fn area(&self) -> f64 {
              std::f64::consts::PI * (self.radius * self.radius)
          }
      }

    Можно задавать несколько блоков impl для типа.

    Если классы предоставляют возможность наследования, то в Rust мы описываем интерфейсы посредством trait'а:

    ExpandedWrap disabled
      trait HasArea {
          fn area(&self) -> f64;
      }


    А реализацию trait'а для нашего типа описываем в соответствующем блоке impl.
    ExpandedWrap disabled
      struct Circle {
          x: f64,
          y: f64,
          radius: f64,
      }
       
      impl HasArea for Circle {
          fn area(&self) -> f64 {
              std::f64::consts::PI * (self.radius * self.radius)
          }
      }
       
      struct Square {
          x: f64,
          y: f64,
          side: f64,
      }
       
      impl HasArea for Square {
          fn area(&self) -> f64 {
              self.side * self.side
          }
      }

    Можно добавлять реализацию того или иного trait'а для того или иного типа, без внесения каких-либо изменений непосредственно в сам тип.

    Наследование же поддерживается только на уровне наследование trait'ов:
    ExpandedWrap disabled
      trait Foo {
          fn foo(&self);
      }
       
      trait FooBar : Foo {
          fn foobar(&self);
      }


    Причем для реализующего trait типа это будет означать, что тип так же должен иметь impl и для "базового" trait'а:
    ExpandedWrap disabled
      struct Baz;
       
      impl Foo for Baz {
          fn foo(&self) { println!("foo"); }
      }
       
      impl FooBar for Baz {
          fn foobar(&self) { println!("foobar"); }
      }


    В trait'ах можно указывать реалиализацию методов по умолчанию:
    ExpandedWrap disabled
      trait Foo {
          fn bar(&self);
       
          fn baz(&self) { println!("We called baz."); }
      }


    Так же trait'ы используются для задания ограничений на generic-параметры, но это совсем другая история...

    Итого, мы имеем три отдельных механизма: для описания интерфейса и иерархии интерфейсов, для задания структур данных и для задания реализаций интерфейсов для тех или иных структур данных. Из плюсов сразу можно указать ортогональность и гибкость, из минусов - сложные описания в случае "классических" ОО-иерархий и полное отсутствие механизма наследования реализаций.

    Небольшой пример с rustbyexample.com(предыдущие примеры были с doc.rust-lang.org):
    ExpandedWrap disabled
      trait Animal {
          // Static method signature; `Self` refers to the implementor type
          fn new(name: &'static str) -> Self;
       
          // Instance methods, only signatures
          fn name(&self) -> &'static str;
          fn noise(&self) -> &'static str;
       
          // A trait can provide default method definitions
          fn talk(&self) {
              // These definitions can access other methods declared in the same
              // trait
              println!("{} says {}", self.name(), self.noise());
          }
      }
       
      struct Dog { name: &'static str }
       
      impl Dog {
          fn wag_tail(&self) {
              println!("{} wags tail", self.name);
          }
      }
       
      // Implement the `Animal` trait for `Dog`
      impl Animal for Dog {
          // Replace `Self` with the implementor type: `Dog`
          fn new(name: &'static str) -> Dog {
              Dog { name: name }
          }
       
          fn name(&self) -> &'static str {
              self.name
          }
       
          fn noise(&self) -> &'static str {
              "woof!"
          }
       
          // Default trait methods can be overridden
          fn talk(&self) {
              // Traits methods can access the implementor methods
              self.wag_tail();
       
              println!("{} says {}", self.name, self.noise());
          }
      }
       
      struct Sheep { naked: bool, name: &'static str }
       
      impl Sheep {
          fn is_naked(&self) -> bool {
              self.naked
          }
       
          fn shear(&mut self) {
              if self.is_naked() {
                  // Implementor methods can use the implementor's trait methods
                  println!("{} is already naked!", self.name());
              } else {
                  println!("{} gets a haircut", self.name);
       
                  self.talk();
                  self.naked = true;
              }
          }
      }
       
      impl Animal for Sheep {
          fn new(name: &'static str) -> Sheep {
              Sheep { name: name, naked: false }
          }
       
          fn name(&self) -> &'static str {
              self.name
          }
       
          fn noise(&self) -> &'static str {
              if self.is_naked() {
                  "baaah"
              } else {
                  "baaaaaaaaaaaah"
              }
          }
      }
       
      fn main() {
          // Type annotation is necessary in this case
          let mut dolly: Sheep = Animal::new("Dolly");
          let spike: Dog = Animal::new("Spike");
          // TODO ^ Try removing the type annotations
       
          dolly.shear();
       
          spike.talk();
          dolly.talk();
      }

    Что это за говнокод? Это форум КОММЕРЧЕСКИХ ПРОГРАММИСТОВ и здесь можно размещать только КОММЕРЧЕСКИЙ КОД.
      Тебя не хватало тут :D
        Осталось определить ПП -- это коммерческая фича или промышленная =)))
          Цитата korvin @
          Лолшто? В ML сигнатуры более чем отделены от реализации. Я уж не говорю про параметризуемые модули(функторы).
          И их можно засунуть в бинарную либу и юзать без исходников? Оооооочень сильно сомневаюсь. Ибо как это сделать, если ML генерит для каждого типа свою реализацию?
            Цитата applegame @
            И их можно засунуть в бинарную либу и юзать без исходников?

            Да. И даже запихнуть в модули.

            Цитата applegame @
            Оооооочень сильно сомневаюсь.

            Это бывает, если вместо чтения документации начинать фантазировать.

            Цитата applegame @
            Ибо как это сделать, если ML генерит для каждого типа свою реализацию?

            RTFM!
            Сообщение отредактировано: korvin -
              Цитата korvin @
              Т.е. проблему останова уже решили? Не думаю, что выдёргивание шнура из розетки --- корректный способ останова рекурсии/цикла.
              Не смешно, korvin. Классическая последовательность Фибоначчи: начальное условие рекурсии задаётся первыми двумя числами. Функция Аккермана: начальные условия задаются парой специализированных формул для выделенных значений аргументов функции. Метод математической индукции: начинается с рассмотрения специального вырожденного случая. Хватит примеров? Да, они АдХоковые, ну и что? Для них именно отдельное поведение требуется по определению. Но далее всё обобщённое. Почему надо удивляться, что моделирование бесконечной сущности тоже требует специального кода?

              Добавлено
              Цитата korvin @
              Оу, ну расскажи нам теорию типов.
              Не поймёте. Даже поняв, не примете, вы даже авторитетов принимать отказываетесь.

              Добавлено
              Цитата D_KEY @
              Шаблоны являются средством параметрического или специального полиморфизма?
              Неправильный вопрос. Не являются, а могут использоваться для. Параметрического. И специального, если оно потребуется, посредством специализаций. А ещё для чистого типизированного лямбда-исчисления посредством метакода, однако тут их возможности ограничены.

              Добавлено
              Цитата korvin @
              Пока нельзя в хэдере написать сигнатуру, а в cpp-файле --- реализацию, скомпилировать его отдельно, и юзать эту функцию, это не ПП, а Сишые макросы (с некоторыми бонуами), не более.
              Уже говорил, что можно. Почему так не делают, это отдельный вопрос. Самый простой ответ на него: это никому не удобно.

              Добавлено
              Цитата D_KEY @
              Но ведь в любой момент кто-то может специализировать тот или иной шаблон.
              Уже говорил, что это означает только лишь то, что при желании или по необходимости полиморфизм можно выключить. Это можно сделать для любого типа полиморфизма. Для динамического я тоже приводил примеры, однако применённый мною к такому ДП твой собственный аргумент касательно ПП ты почему-то опроверг, и я так и не понял, почему так нельзя для ПП, но можно для ДП. А ещё я могу отключить СП тривиальнейшим кастом типа функции. Что внезапно тоже является разновидностью СП. D_KEY, ты ещё не запутался в своих критериях применимости своих аргументов к своему виденью критериев наличия полиморфизма?
              Сообщение отредактировано: Qraizer -
                Цитата Qraizer @
                Цитата korvin @
                Оу, ну расскажи нам теорию типов.
                Не поймёте. Даже поняв, не примете, вы даже авторитетов принимать отказываетесь.

                В качестве авторитетов ты предлагал пока только сам себя. Тебе же тут цитировали вики, работы, tapl и стандарт.

                Цитата
                Цитата D_KEY @
                Шаблоны являются средством параметрического или специального полиморфизма?
                Неправильный вопрос.

                Правильный.

                Цитата
                Не являются, а могут использоваться для.

                Имитации параметрического.

                Цитата
                Параметрического. И специального, если оно потребуется, посредством специализаций. А ещё для чистого типизированного лямбда-исчисления посредством метакода, однако тут их возможности ограничены.


                У тебя каша в аргументации. Разговор о виде полиморфизма, к которому относятся шаблоны.

                Цитата
                Цитата D_KEY @
                Но ведь в любой момент кто-то может специализировать тот или иной шаблон.
                Уже говорил, что это означает только лишь то, что при желании или по необходимости полиморфизм можно выключить.


                А с чего ты взял, что он был включен? У тебя компилятор обязан создавать специализации(на уровне языка, а не генерации кода в реализации), а ты всегда имеешь возможность этими специализациями управлять. Где тут ПП?

                Цитата
                Это можно сделать для любого типа полиморфизма. Для динамического я тоже приводил примеры, однако применённый мною к такому ДП твой собственный аргумент касательно ПП ты почему-то опроверг, и я так и не понял, почему так нельзя для ПП, но можно для ДП.

                Я объяснил. Ты не отключал специальный полиморфизм, а явно выбрал функцию и вызвал её. Ты сделал неполиморфный вызов. В случае же шаблонов у тебя всегда параметрическая полиморфность нарушена, т.к. нет гарантии однородности. Делая как бы полиморфный вызов ты не знаешь, будет ли там дефолтная реализация или какая-то переопределенная. В лучших традициях ad-hoc.

                Цитата
                А ещё я могу отключить СП тривиальнейшим кастом типа функции. Что внезапно тоже является разновидностью СП.

                Ты ничего не можешь отключить. Ты просто вместо полиморфного вызова делаешь обычный.

                Добавлено
                Цитата Qraizer @
                D_KEY, ты ещё не запутался в своих критериях применимости своих аргументов к своему виденью критериев наличия полиморфизма?

                А ты все ещё думаешь, что обсуждается наличие полиморфизма, а не его вид?
                Сообщение отредактировано: D_KEY -
                  Цитата korvin @
                  Да. И даже запихнуть в модули.
                  Рассмотрим простую параметрически полиморфную функцию:
                  ExpandedWrap disabled
                    foo a b = a + b

                  Ты полагаешь, что ее можно успешно засунуть в бинарную библиотеку оставив наружу только сигнатуру вкомпилировав в либу тело "a + b"? Как ты себе представляешь ABI, которое обеспечит вызов такой функции? Допустим ты сделаешь боксинг аргументов и передашь эти void* неизвестно с чем в либу. Полиморфная функция foo должна отправить эти void* в уже неполиморфную функцию "+", которой нужно знать как именно сложить эти аргументы. И тут получается облом - типы неизвестны.
                  Забавно, но Хаскель тебе не даст даже сигнатуру написать для такой функции, либо разрешит, но заставит указать принадлежность аргументов к тайпклассу, превратив таким образом функцию в параметрически неполиморфную.
                  ИМХО невозможно для параметрически полиморфной функции жестко отделить сигнатуру от реализации, ни в каком языке. Как компилятор на клиентской стороне будет делать тайп-чекинг если у него нет под рукой исходного кода этой функции? Мамой кланус эта функция умеет складывать целые числа, пиццу и кошек.
                  Цитата korvin @
                  RTFM!
                  То есть ты, надо думать, уже прочитал этот факинг мануал. Не мог бы ты тогда дать ссылочку на описание ABI обеспечивющей экспорт только сигнатур полиморфных функций без тела. А то я для MLton только смог найти ABI для обычных сишных функций и инфу о том, что, что MLton не поддерживает раздельную компиляцию совсем.
                  Цитата Qraizer @
                  Уже говорил, что можно.
                  Если шаблон на самом деле параметрически полиморфен, то полноценно экспортировать чисто сигнататуру без тела не получится. Только частично - конечное число реализаций. Если же в либе нет нужной реализации, то компилятор на клиентской стороне не сможет сгенерить ее без тела шаблона.
                  Сообщение отредактировано: applegame -
                    Цитата applegame @
                    Рассмотрим простую параметрически полиморфную функцию:
                    ExpandedWrap disabled
                      foo a b = a + b

                    Как ты собрался скаладывать значения в параметрически полиморфной функции?
                    Сообщение отредактировано: D_KEY -
                      Цитата D_KEY @
                      Как ты собрался скаладывать значения в параметрически полиморфной функции?
                      Я не собираюсь их складывать, я собираюсь их передать неполиморфной функции сложения. Собственно так в полиморфных функциях и происходит.

                      Добавлено
                      Пардон, должно быть вот так:
                      Цитата applegame @
                      Я не собираюсь их складывать, я собираюсь их передать параметрически неполиморфной функции сложения. Собственно так в параметрически полиморфных функциях и происходит.
                        Цитата applegame @
                        Я не собираюсь их складывать, я собираюсь их передать неполиморфной функции сложения.

                        Хорошо. Как ты собираешься в параметрически полиморфной функции передавать значения неизвестных типов в неполиморфную функцию?

                        Добавлено
                        Цитата applegame @
                        Собственно так в параметрически полиморфных функциях и происходит.

                        Это где такое?
                          Цитата D_KEY @
                          Хорошо. Как ты собираешься в параметрически полиморфной функции передавать значения неизвестных типов в неполиморфную функцию?
                          Компилятор зная тип сам выполнит вызов нужной версии функции сложения или это будет сделано в run-time через нечто подобное таблице виртуальных функций.
                          Я вот не пойму, ты оспариваешь параметрическую полиморфность функции "foo a b = a + b"?
                          Цитата D_KEY @
                          Это где такое?
                          Везде в реальных программах. Сферический параметрический полиморфизм в вакууме не существует, в жестокой реальности любая ПП-функция рано или поздно упрется в ad-hoc полиморфизм.
                          Сообщение отредактировано: applegame -
                            Цитата applegame @
                            Компилятор зная тип сам выполнит вызов нужной версии функции сложения

                            Какой нужной версии? Ты же говоришь о вызове неполиморфной функции.

                            Цитата
                            Я вот не пойму, ты оспариваешь параметрическую полиморфность функции "foo a b = a + b"?

                            Я оспариваю корректность вызова функции сложения в параметрически полиморфной функции.

                            Цитата
                            Сферический параметрический полиморфизм в вакууме не существует, в жестокой реальности любая ПП-функция рано или поздно упрется в ad-hoc полиморфизм.

                            Чем докажешь?
                              applegame, любая генерация кода по некоторым параметрам является параметрическим полиморфизмом?
                                Полный бред написал, D_KEY, извини. Один пример:
                                Цитата
                                Цитата
                                Цитата D_KEY @
                                Шаблоны являются средством параметрического или специального полиморфизма?
                                Неправильный вопрос.
                                Правильный.
                                Шаблоны; не являются; средством; какого-то там полиморфизма. Точно так же как классы не являются средством для ООП. И те, и другие – могут; для; этого использоваться. И далее в том же духе. Но уже этой цитаты достаточно, чтобы скомпрометировать любые твои предшествующие посты. Перед продолжением дискуссии настоятельно советую тебе освежить свои знания о теории, и особенно о Плюсах.

                                Добавлено
                                Цитата applegame @
                                Если шаблон на самом деле параметрически полиморфен, то полноценно экспортировать чисто сигнататуру без тела не получится. Только частично - конечное число реализаций. Если же в либе нет нужной реализации, то компилятор на клиентской стороне не сможет сгенерить ее без тела шаблона.
                                Может. Тела шаблона для этого не требуется, достаточно сгенерённого грамматического дерева, каковое полностью строится в точке определения, а не инстанцирования.
                                Сообщение отредактировано: Qraizer -
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (33) « Первая ... 29 30 [31] 32 33 


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,1018 ]   [ 15 queries used ]   [ Generated: 2.05.24, 06:29 GMT ]