Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.223.32.230] |
|
Страницы: (33) « Первая ... 29 30 [31] 32 33 ( Перейти к последнему сообщению ) |
Сообщ.
#451
,
|
|
|
Цитата D_KEY @ Предлагаю похоливарить на данную тему. Коротко о trait'ах, impl'ах и данных на примере Rust. Вместо "классического" ОО подхода, Rust предоставляет отдельные ортогональные механизмы. Если классы у нас описывают и методы и данные, то в Rust мы задаем отдельно данные: struct Circle { x: f64, y: f64, radius: f64, } и отдельно наборы методов: impl Circle { fn area(&self) -> f64 { std::f64::consts::PI * (self.radius * self.radius) } } Можно задавать несколько блоков impl для типа. Если классы предоставляют возможность наследования, то в Rust мы описываем интерфейсы посредством trait'а: trait HasArea { fn area(&self) -> f64; } А реализацию trait'а для нашего типа описываем в соответствующем блоке impl. 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'ов: trait Foo { fn foo(&self); } trait FooBar : Foo { fn foobar(&self); } Причем для реализующего trait типа это будет означать, что тип так же должен иметь impl и для "базового" trait'а: struct Baz; impl Foo for Baz { fn foo(&self) { println!("foo"); } } impl FooBar for Baz { fn foobar(&self) { println!("foobar"); } } В trait'ах можно указывать реалиализацию методов по умолчанию: trait Foo { fn bar(&self); fn baz(&self) { println!("We called baz."); } } Так же trait'ы используются для задания ограничений на generic-параметры, но это совсем другая история... Итого, мы имеем три отдельных механизма: для описания интерфейса и иерархии интерфейсов, для задания структур данных и для задания реализаций интерфейсов для тех или иных структур данных. Из плюсов сразу можно указать ортогональность и гибкость, из минусов - сложные описания в случае "классических" ОО-иерархий и полное отсутствие механизма наследования реализаций. Небольшой пример с rustbyexample.com(предыдущие примеры были с doc.rust-lang.org): 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(); } Что это за говнокод? Это форум КОММЕРЧЕСКИХ ПРОГРАММИСТОВ и здесь можно размещать только КОММЕРЧЕСКИЙ КОД. |
Сообщ.
#452
,
|
|
|
Тебя не хватало тут
|
Сообщ.
#453
,
|
|
|
Осталось определить ПП -- это коммерческая фича или промышленная =)))
|
Сообщ.
#454
,
|
|
|
Цитата korvin @ И их можно засунуть в бинарную либу и юзать без исходников? Оооооочень сильно сомневаюсь. Ибо как это сделать, если ML генерит для каждого типа свою реализацию? Лолшто? В ML сигнатуры более чем отделены от реализации. Я уж не говорю про параметризуемые модули(функторы). |
Сообщ.
#455
,
|
|
|
Цитата applegame @ И их можно засунуть в бинарную либу и юзать без исходников? Да. И даже запихнуть в модули. Цитата applegame @ Оооооочень сильно сомневаюсь. Это бывает, если вместо чтения документации начинать фантазировать. Цитата applegame @ Ибо как это сделать, если ML генерит для каждого типа свою реализацию? RTFM! |
Сообщ.
#456
,
|
|
|
Цитата korvin @ Не смешно, korvin. Классическая последовательность Фибоначчи: начальное условие рекурсии задаётся первыми двумя числами. Функция Аккермана: начальные условия задаются парой специализированных формул для выделенных значений аргументов функции. Метод математической индукции: начинается с рассмотрения специального вырожденного случая. Хватит примеров? Да, они АдХоковые, ну и что? Для них именно отдельное поведение требуется по определению. Но далее всё обобщённое. Почему надо удивляться, что моделирование бесконечной сущности тоже требует специального кода? Т.е. проблему останова уже решили? Не думаю, что выдёргивание шнура из розетки --- корректный способ останова рекурсии/цикла. Добавлено Не поймёте. Даже поняв, не примете, вы даже авторитетов принимать отказываетесь. Добавлено Неправильный вопрос. Не являются, а могут использоваться для. Параметрического. И специального, если оно потребуется, посредством специализаций. А ещё для чистого типизированного лямбда-исчисления посредством метакода, однако тут их возможности ограничены. Добавлено Цитата korvin @ Уже говорил, что можно. Почему так не делают, это отдельный вопрос. Самый простой ответ на него: это никому не удобно. Пока нельзя в хэдере написать сигнатуру, а в cpp-файле --- реализацию, скомпилировать его отдельно, и юзать эту функцию, это не ПП, а Сишые макросы (с некоторыми бонуами), не более. Добавлено Уже говорил, что это означает только лишь то, что при желании или по необходимости полиморфизм можно выключить. Это можно сделать для любого типа полиморфизма. Для динамического я тоже приводил примеры, однако применённый мною к такому ДП твой собственный аргумент касательно ПП ты почему-то опроверг, и я так и не понял, почему так нельзя для ПП, но можно для ДП. А ещё я могу отключить СП тривиальнейшим кастом типа функции. Что внезапно тоже является разновидностью СП. D_KEY, ты ещё не запутался в своих критериях применимости своих аргументов к своему виденью критериев наличия полиморфизма? |
Сообщ.
#457
,
|
|
|
Цитата Qraizer @ Не поймёте. Даже поняв, не примете, вы даже авторитетов принимать отказываетесь. В качестве авторитетов ты предлагал пока только сам себя. Тебе же тут цитировали вики, работы, tapl и стандарт. Цитата Неправильный вопрос. Правильный. Цитата Не являются, а могут использоваться для. Имитации параметрического. Цитата Параметрического. И специального, если оно потребуется, посредством специализаций. А ещё для чистого типизированного лямбда-исчисления посредством метакода, однако тут их возможности ограничены. У тебя каша в аргументации. Разговор о виде полиморфизма, к которому относятся шаблоны. Цитата Уже говорил, что это означает только лишь то, что при желании или по необходимости полиморфизм можно выключить. А с чего ты взял, что он был включен? У тебя компилятор обязан создавать специализации(на уровне языка, а не генерации кода в реализации), а ты всегда имеешь возможность этими специализациями управлять. Где тут ПП? Цитата Это можно сделать для любого типа полиморфизма. Для динамического я тоже приводил примеры, однако применённый мною к такому ДП твой собственный аргумент касательно ПП ты почему-то опроверг, и я так и не понял, почему так нельзя для ПП, но можно для ДП. Я объяснил. Ты не отключал специальный полиморфизм, а явно выбрал функцию и вызвал её. Ты сделал неполиморфный вызов. В случае же шаблонов у тебя всегда параметрическая полиморфность нарушена, т.к. нет гарантии однородности. Делая как бы полиморфный вызов ты не знаешь, будет ли там дефолтная реализация или какая-то переопределенная. В лучших традициях ad-hoc. Цитата А ещё я могу отключить СП тривиальнейшим кастом типа функции. Что внезапно тоже является разновидностью СП. Ты ничего не можешь отключить. Ты просто вместо полиморфного вызова делаешь обычный. Добавлено Цитата Qraizer @ D_KEY, ты ещё не запутался в своих критериях применимости своих аргументов к своему виденью критериев наличия полиморфизма? А ты все ещё думаешь, что обсуждается наличие полиморфизма, а не его вид? |
Сообщ.
#458
,
|
|
|
Цитата korvin @ Рассмотрим простую параметрически полиморфную функцию:Да. И даже запихнуть в модули. foo a b = a + b Ты полагаешь, что ее можно успешно засунуть в бинарную библиотеку оставив наружу только сигнатуру вкомпилировав в либу тело "a + b"? Как ты себе представляешь ABI, которое обеспечит вызов такой функции? Допустим ты сделаешь боксинг аргументов и передашь эти void* неизвестно с чем в либу. Полиморфная функция foo должна отправить эти void* в уже неполиморфную функцию "+", которой нужно знать как именно сложить эти аргументы. И тут получается облом - типы неизвестны. Забавно, но Хаскель тебе не даст даже сигнатуру написать для такой функции, либо разрешит, но заставит указать принадлежность аргументов к тайпклассу, превратив таким образом функцию в параметрически неполиморфную. ИМХО невозможно для параметрически полиморфной функции жестко отделить сигнатуру от реализации, ни в каком языке. Как компилятор на клиентской стороне будет делать тайп-чекинг если у него нет под рукой исходного кода этой функции? Мамой кланус эта функция умеет складывать целые числа, пиццу и кошек. Цитата korvin @ То есть ты, надо думать, уже прочитал этот факинг мануал. Не мог бы ты тогда дать ссылочку на описание ABI обеспечивющей экспорт только сигнатур полиморфных функций без тела. А то я для MLton только смог найти ABI для обычных сишных функций и инфу о том, что, что MLton не поддерживает раздельную компиляцию совсем.RTFM! Цитата Qraizer @ Если шаблон на самом деле параметрически полиморфен, то полноценно экспортировать чисто сигнататуру без тела не получится. Только частично - конечное число реализаций. Если же в либе нет нужной реализации, то компилятор на клиентской стороне не сможет сгенерить ее без тела шаблона. Уже говорил, что можно. |
Сообщ.
#459
,
|
|
|
Цитата applegame @ Рассмотрим простую параметрически полиморфную функцию: foo a b = a + b Как ты собрался скаладывать значения в параметрически полиморфной функции? |
Сообщ.
#460
,
|
|
|
Цитата D_KEY @ Я не собираюсь их складывать, я собираюсь их передать неполиморфной функции сложения. Собственно так в полиморфных функциях и происходит. Как ты собрался скаладывать значения в параметрически полиморфной функции? Добавлено Пардон, должно быть вот так: Цитата applegame @ Я не собираюсь их складывать, я собираюсь их передать параметрически неполиморфной функции сложения. Собственно так в параметрически полиморфных функциях и происходит. |
Сообщ.
#461
,
|
|
|
Цитата applegame @ Я не собираюсь их складывать, я собираюсь их передать неполиморфной функции сложения. Хорошо. Как ты собираешься в параметрически полиморфной функции передавать значения неизвестных типов в неполиморфную функцию? Добавлено Цитата applegame @ Собственно так в параметрически полиморфных функциях и происходит. Это где такое? |
Сообщ.
#462
,
|
|
|
Цитата D_KEY @ Компилятор зная тип сам выполнит вызов нужной версии функции сложения или это будет сделано в run-time через нечто подобное таблице виртуальных функций.Хорошо. Как ты собираешься в параметрически полиморфной функции передавать значения неизвестных типов в неполиморфную функцию? Я вот не пойму, ты оспариваешь параметрическую полиморфность функции "foo a b = a + b"? Цитата D_KEY @ Везде в реальных программах. Сферический параметрический полиморфизм в вакууме не существует, в жестокой реальности любая ПП-функция рано или поздно упрется в ad-hoc полиморфизм. Это где такое? |
Сообщ.
#463
,
|
|
|
Цитата applegame @ Компилятор зная тип сам выполнит вызов нужной версии функции сложения Какой нужной версии? Ты же говоришь о вызове неполиморфной функции. Цитата Я вот не пойму, ты оспариваешь параметрическую полиморфность функции "foo a b = a + b"? Я оспариваю корректность вызова функции сложения в параметрически полиморфной функции. Цитата Сферический параметрический полиморфизм в вакууме не существует, в жестокой реальности любая ПП-функция рано или поздно упрется в ad-hoc полиморфизм. Чем докажешь? |
Сообщ.
#464
,
|
|
|
applegame, любая генерация кода по некоторым параметрам является параметрическим полиморфизмом?
|
Сообщ.
#465
,
|
|
|
Полный бред написал, D_KEY, извини. Один пример:
Цитата Шаблоны; не являются; средством; какого-то там полиморфизма. Точно так же как классы не являются средством для ООП. И те, и другие – могут; для; этого использоваться. И далее в том же духе. Но уже этой цитаты достаточно, чтобы скомпрометировать любые твои предшествующие посты. Перед продолжением дискуссии настоятельно советую тебе освежить свои знания о теории, и особенно о Плюсах. Цитата Правильный.Неправильный вопрос. Добавлено Цитата applegame @ Может. Тела шаблона для этого не требуется, достаточно сгенерённого грамматического дерева, каковое полностью строится в точке определения, а не инстанцирования. Если шаблон на самом деле параметрически полиморфен, то полноценно экспортировать чисто сигнататуру без тела не получится. Только частично - конечное число реализаций. Если же в либе нет нужной реализации, то компилятор на клиентской стороне не сможет сгенерить ее без тела шаблона. |