Есть такой тип object. С ним можно вытварять очень много. Есть так же рефлексия с помощью которой хочть черта лысого можно динамически вызвать. Но C# — это статически типизированный язык. Если хотити динамики, то их есть у меня. Есть VB.NET с той самой "утиной типизацией", кстати в 9.0 с ней даже по круче будет. Там придумали "утиные интерфесы" — т.е. описываешь интерфейс как "утиный" и приводишь в рантайме к нему любой объект... если у объектоа методы совпадают, то можно вызвать методы через утиный интерфейс. Что это дает? А тот самый комплит ворд и подсказки среды, плюс еще возможность обнаружить ошибку при инициализации ссылки на интерфейс, а не при вызове 101-вого метода. Далее создали динамические переменные. Когда можно намисать та:
a = "SomeMethodName"
...
b.a(x, y)
за синтаксис не ручвюсь, но смысл думаю понятен.
Но это все из другой оперы. Это все для скриптов. А в нормальных ОО-программах типизация должна быть типзацией, а не утиными историями.
Java/C# не являются ни развитием, ни "осознанием ошибок" C++. Они взяли наихудшую парадигму из языка и возвели ее в степень догмы. А именно — идею наследования. Наследование — это самая большая провокация в индустрии. Ни в каком моделировании наследования не существует и в реальной жизни тоже — ни в электронике, ни в бухгалтерии, ни где бы то ни было еще. Есть одно — генеология. Но это не имеет ни малешего отношения к тому, что называется наследованием в программировании. Все эти многоэтажные иерархии классов только усложняют жизнь, вместо того, чтобы упрощать. И служат они одной единственной цели — раздувать и дальше этот мыльный пузырь и продолжать кормить миллиарды индусов. В результате этой идеи возникла дутая индустрия, не обеспеченная никакими реальными активами. А вся мировая практика говорит о том, что рано или поздно этот пузырь лопнет.
Так вот мне интересно, не является ли Duck typing следующей парадигмой после ООП? Ведь в duck typing нет отношения "is-a", а есть что-то типа "like-a" ("can", "respond_to"). Т.е., наследования нет, а полиморфизм, благодоря динамической типизации, есть.
Может быть ООП уже исчерпала себя (как в свое время структурное программирование) и сейчас мы наблюдаем за возникновением новой парадигмы?
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Так вот мне интересно, не является ли Duck typing следующей парадигмой после ООП? Ведь в duck typing нет отношения "is-a", а есть что-то типа "like-a" ("can", "respond_to"). Т.е., наследования нет, а полиморфизм, благодоря динамической типизации, есть.
E>Может быть ООП уже исчерпала себя (как в свое время структурное программирование) и сейчас мы наблюдаем за возникновением новой парадигмы?
Кстати, динамическая типизация тут не обязательна. В С++ возможно объявить шаблонную функцию, которая будет рассчитывать на наличие определенных методов у своих аргументов — и это будет то же самое (только эти требования нигде в коде явно не прописаны, что плохо). Например, в качестве итератора можно передать какой угодно объект, имеющий оператор ++ (и может быть + и -), а в качестве аллокатора соответственно передается любой класс, имеющий такой же набор методов.
Здравствуйте, Кодёнок, Вы писали:
E>>Так вот мне интересно, не является ли Duck typing следующей парадигмой после ООП? Ведь в duck typing нет отношения "is-a", а есть что-то типа "like-a" ("can", "respond_to"). Т.е., наследования нет, а полиморфизм, благодоря динамической типизации, есть.
E>>Может быть ООП уже исчерпала себя (как в свое время структурное программирование) и сейчас мы наблюдаем за возникновением новой парадигмы?
Кё>Кстати, динамическая типизация тут не обязательна. В С++ возможно объявить шаблонную функцию, которая будет рассчитывать на наличие определенных методов у своих аргументов — и это будет то же самое (только эти требования нигде в коде явно не прописаны, что плохо). Например, в качестве итератора можно передать какой угодно объект, имеющий оператор ++ (и может быть + и -), а в качестве аллокатора соответственно передается любой класс, имеющий такой же набор методов.
Есть небольшое отличие: динамические языки проще адаптировать к некоторым условиям. Например, нужно прочитать из потока заголовок, определить, сколько байт нужно пропустить, а затем прочитать еще несколько байт. Если потоком является файл, то можно просто сделать seek, а если потоком является сокет, то пропускаемые данные нужно читать:
def load_header_and_data( stream )
h = load_header( stream )
if stream.respond_to( "seek" )
stream.seek( h.get_length() )
else
stream.read( h.get_length() )
end
load_data( stream )
end
E>Так вот мне интересно, не является ли Duck typing следующей парадигмой после ООП? Ведь в duck typing нет отношения "is-a", а есть что-то типа "like-a" ("can", "respond_to"). Т.е., наследования нет, а полиморфизм, благодоря динамической типизации, есть.
Так вроде Duck typing обобщенное программирование в чистом виде, а это довольно старая парадигма
Здравствуйте, FR, Вы писали:
E>>Так вот мне интересно, не является ли Duck typing следующей парадигмой после ООП? Ведь в duck typing нет отношения "is-a", а есть что-то типа "like-a" ("can", "respond_to"). Т.е., наследования нет, а полиморфизм, благодоря динамической типизации, есть.
FR>Так вроде Duck typing обобщенное программирование в чистом виде, а это довольно старая парадигма
На момент появления C++ ООП так же было старой парадигмой
In computer science, generics is a technique that allows one value to take different datatypes (so-called polymorphism) as long as certain contracts such as subtypes and signature are kept. The programming style emphasizing use of this technique is called generic programming.
Duck typing -- это обобщенное программирование в терминах signatures. А обобщенное программирование в C#/Java -- в терминах subtypes, т.е. в рамках традиционного ООП с наследованием.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Duck typing -- это обобщенное программирование в терминах signatures. А обобщенное программирование в C#/Java -- в терминах subtypes, т.е. в рамках традиционного ООП с наследованием.
) E>>Чесно говоря, подобный duck typing в C++ меня бы забабахал сразу же.
Кё>Ну это недостаток лично С++ (дело все лишь в добавлении одной фичи, аналогичной typeof или sizeof), а не статически типизированных языков.
Ok. А как бы это выглядело со статически типизированным C# и его generic-ами? Можно ли там будет добавить такое ключевое слово, которое можно будет применить к параметру шаблона?
Здравствуйте, eao197, Вы писали:
E>Может быть ООП уже исчерпала себя (как в свое время структурное программирование) и сейчас мы наблюдаем за возникновением новой парадигмы?
Ну, возможно все-таки исчерпала. Статически типизированное ООП само по себе — штука очень простая. После длительного шатания из стороны в сторону все-таки пришли к более-менее единому знаменателю в виде классов/интерфейсов.
Дальнейшее развитие ООП-мейнстрима почему-то идет по пути
а) встраивания паттернов в язык — т.е. развитие над-ООП надстроек
б) введение ортогональных парадигм — например, generics.
Наверное, как раз оттого, что улучшать ООП уже некуда.
Duck typing, в принципе, не обязан работать динамически. Его можно было бы ввести, например, в constraintы generic. Т.е. вместо введения интерфейса ICountable { int Count { get; } } и заставления всех мыслимых параметров шаблона явно от него наследоваться при помощи
class SmartType<T>
where T: ICountable
{
public static int q(T param) { return t.Count;}
}
мы бы вводили утиный интерфейс ICountable, который бы вынуждал выполнять биндинг на этапе инстанцирования дженерика. Вся информация в принципе есть; особой тяжести здесь нету — операция выполняется единожды для каждого типа.
В отличие от, скажем, приведения произвольного object к нашему интерфейсу, которое не удастся сделать привычным ловким методом дотнета.
... << RSDN@Home 1.1.4 stable rev. 510>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, eao197, Вы писали:
E>>Может быть ООП уже исчерпала себя (как в свое время структурное программирование) и сейчас мы наблюдаем за возникновением новой парадигмы?
S>Duck typing, в принципе, не обязан работать динамически. Его можно было бы ввести, например, в constraintы generic. Т.е. вместо введения интерфейса ICountable { int Count { get; } } и заставления всех мыслимых параметров шаблона явно от него наследоваться при помощи S>
S>class SmartType<T>
S>where T: ICountable
S>{
S> public static int q(T param) { return t.Count;}
S>}
S>
S>мы бы вводили утиный интерфейс ICountable, который бы вынуждал выполнять биндинг на этапе инстанцирования дженерика. Вся информация в принципе есть; особой тяжести здесь нету — операция выполняется единожды для каждого типа. S>В отличие от, скажем, приведения произвольного object к нашему интерфейсу, которое не удастся сделать привычным ловким методом дотнета.
Здравствуйте, eao197, Вы писали:
E>Ok. А как бы это выглядело со статически типизированным C# и его generic-ами? Можно ли там будет добавить такое ключевое слово, которое можно будет применить к параметру шаблона?
has_method должен быть инструкцией компилятору, т.е. полностью выполняться во время компиляции, и быть замененным на результат. Как sizeof в C++. Тогда has_method может принимать идентификаторы или строковые литералы (has_method(stream, "Seek")), т.к. разницы особой нет (разве что строковые литералы можно "склеить" с другими и потенциально ввести еще инструкции для разбора строк во время компиляции, т.е. возможностей с ними больше).
Единственное условие — чтобы код, который никогда не выполнится (if (false) ...), не проверялся на корректность. Более сложный вариант — чтобы проверялся весь код, кроме обращений к методам, которые пытались найти с помощью has_method. Т.е. если метода Seek нет, но компилятор видит, что программист использовал has_method, чтобы его найти, он не проверяет весь стейтмент. Что лучше, не знаю.
Здравствуйте, Кодёнок, Вы писали:
E>>Ok. А как бы это выглядело со статически типизированным C# и его generic-ами? Можно ли там будет добавить такое ключевое слово, которое можно будет применить к параметру шаблона?
Кё>Теоретически — нет проблем, так же как и в С++.
<...код поскипан...> Кё>has_method должен быть инструкцией компилятору, т.е. полностью выполняться во время компиляции, и быть замененным на результат. Как sizeof в C++. Тогда has_method может принимать идентификаторы или строковые литералы (has_method(stream, "Seek")), т.к. разницы особой нет (разве что строковые литералы можно "склеить" с другими и потенциально ввести еще инструкции для разбора строк во время компиляции, т.е. возможностей с ними больше).
, то оказывается, что в отличии от generic-ов Java, generic-и C# предназначены для инстанциирования в run-time (не compile-time). Поэтому компилятор на этапе компиляции приведенного тобой кода не сможет понять, какая сигнатура будет у метода Seek.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Есть такая штука: Duck typing. В языках, вроде Smalltalk, Python и Ruby она активно используется.
За Python и Ruby не скажу — дела с ними не имел, а Smalltalk — это одна сплошная "утиная история", подругому на нем писать нету синтаксических возможностей.
E>Так вот мне интересно, не является ли Duck typing следующей парадигмой после ООП? Ведь в duck typing нет отношения "is-a", а есть что-то типа "like-a" ("can", "respond_to"). Т.е., наследования нет, а полиморфизм, благодоря динамической типизации, есть.
Типизация и ОО — вещи абсолютно ортогональные. ОО — способ смотреть на мир. С точки зрения ОО весь мир — объекты, с все взаимодействия между объектами — посылка сообщений. О типизации ОО вообще ничего не говорит.
Типизация бывает статической и динамической.
Статическая это вид верификации. На код накладываются дополнительные ограничения и компилятор их проверяет. Выявляет некоторые ошибки до старта программы и дает некоторые гарантии. В частности, компилятор гарантирует, что объект обязался понимать посланное ему сообщение (там где отсутствует явное приведение типов).
Исторически статическая типизаия использовалась как способ дать компилятору подскази для построения эффективного кода. Например, С++ компилятор, строит vtbl для класса размером не на все возможные (в системе) сообщения, а только на определенные в этом классе. В Smalltalk, например, такой оптимизации не делается. По этому если Smalltalk объект получает "непонятное" для него сообщение, то он кидает исключение, а C++ объект начинает вести себя непредсказуемым образом (что почти всегда приводит к GPF, а иногда к порче данных или странному поведению).
Динамическая типизация это просто наличие у объекта такого свойства как тип. Отсутвие такого свойства никак не мешает ему быть объектом, т.е. реагировать на сообщения (пример — Self).
Более того, типизация несколько мешает ОО. Чистое объектное видение мира подразумевает, что любой объект потенциально может отреагировать на любое сообщение. Или другими словами есть только объекты и объекты не различаются ничем, кроме своего поведения. Например, к каждому человеку можно подойти с вопросом "Сколько ты будешь делать?" с параметром ТЗ. На что можно получить в ответ "N дней", "Чего???" или по зубам . Но коллапса с миром не случит в любом случае.
E>Еще есть несколько интересных обсуждений: Следующий язык программирования
E>Есть такой тип object. С ним можно вытварять очень много. Есть так же рефлексия с помощью которой хочть черта лысого можно динамически вызвать. Но C# — это статически типизированный язык. Если хотити динамики, то их есть у меня. Есть VB.NET с той самой "утиной типизацией", кстати в 9.0 с ней даже по круче будет. Там придумали "утиные интерфесы" — т.е. описываешь интерфейс как "утиный" и приводишь в рантайме к нему любой объект... если у объектоа методы совпадают, то можно вызвать методы через утиный интерфейс. Что это дает? А тот самый комплит ворд и подсказки среды, плюс еще возможность обнаружить ошибку при инициализации ссылки на интерфейс, а не при вызове 101-вого метода. Далее создали динамические переменные. Когда можно намисать та:
Это еще один пример как можно совмещать прелести верификации с ОО.
:
E>[q]
E>Java/C# не являются ни развитием, ни "осознанием ошибок" C++. Они взяли наихудшую парадигму из языка и возвели ее в степень догмы. А именно — идею наследования. Наследование — это самая большая провокация в индустрии. Ни в каком моделировании наследования не существует и в реальной жизни тоже — ни в электронике, ни в бухгалтерии, ни где бы то ни было еще. Есть одно — генеология. Но это не имеет ни малешего отношения к тому, что называется наследованием в программировании. Все эти многоэтажные иерархии классов только усложняют жизнь, вместо того, чтобы упрощать. И служат они одной единственной цели — раздувать и дальше этот мыльный пузырь и продолжать кормить миллиарды индусов. В результате этой идеи возникла дутая индустрия, не обеспеченная никакими реальными активами. А вся мировая практика говорит о том, что рано или поздно этот пузырь лопнет.
С этой мыслью, я не спорю, но она imho к вопросу отношния не имеет. Скорее к вопросу, какие парадигмы есть возможность сделать mainstream.
E>Может быть ООП уже исчерпала себя (как в свое время структурное программирование) и сейчас мы наблюдаем за возникновением новой парадигмы?
"Утиные истории" появились задолго до ОО, например тот же Lisp.
Здравствуйте, eao197, Вы писали: E>Ok. А как бы это выглядело со статически типизированным C# и его generic-ами?
С дженериками — никак. Потому, что такая базовая вещь, как поток, не должна вводиться через дженерик. Вот так выглядит код на реальном шарпе:
public void LoadHeaderAndData(Stream stream)
{
Header h = LoadHeader(stream);
if(stream.CanSeek())
stream.Seek(h.GetSkipLength());
else
{
byte[] buffer = new byte[h.GetSkipLength()];
stream.Read(buffer, 0, h.GetSkipLength());
}
LoadData(stream);
}
... << RSDN@Home 1.1.4 stable rev. 510>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Dyoma, Вы писали:
E>>Есть такая штука: Duck typing. В языках, вроде Smalltalk, Python и Ruby она активно используется.
D>За Python и Ruby не скажу — дела с ними не имел, а Smalltalk — это одна сплошная "утиная история", подругому на нем писать нету синтаксических возможностей.
Забыл сюда добавить про движение ровно в противоположную сторону — StrongTalk. Он, к сожалению, так и остался академической разработкой, замятой компанией Sun. Идея заключалась в прикручивании к Smalltalk, системы типов, для целей верификации, подсказок IDE, и может еще чего.
StrongTalk расширяет синтаксис Smalltalk, добавляя опциональные ограничения на тип параметров. Ограничения могут иметь вид:
это параметр понимает такой-то протокол
понимает список протоколов — объединение протоколов.
понимает один из списка протоколов — пересечение.
Протокол — это так в Smalltalk называется понятие более известное как interface.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, eao197, Вы писали: E>>Ok. А как бы это выглядело со статически типизированным C# и его generic-ами? S>С дженериками — никак. Потому, что такая базовая вещь, как поток, не должна вводиться через дженерик.
Это почему? Где-то потоком будет файл. Где-то строка. Где-то сокет.
Или вокруг этого какие-то обертки, реализующие некоторый интерфейс строить придется?
S> Вот так выглядит код на реальном шарпе:
S>
Здравствуйте, Dyoma, Вы писали:
E>>Так вот мне интересно, не является ли Duck typing следующей парадигмой после ООП? Ведь в duck typing нет отношения "is-a", а есть что-то типа "like-a" ("can", "respond_to"). Т.е., наследования нет, а полиморфизм, благодоря динамической типизации, есть.
D>Типизация и ОО — вещи абсолютно ортогональные. ОО — способ смотреть на мир. С точки зрения ОО весь мир — объекты, с все взаимодействия между объектами — посылка сообщений. О типизации ОО вообще ничего не говорит.
А я про типизацию-то в данной фразе и не говорил. Я имел в виду, что в ООП мы используем отношение "is-a" для определения взаимосвязи между сущностями. Отсюда и необходимость выстраивать иерархии наследования. А если брать duck typing, то наследование здесь вообще пофигу, нет никакого "is-a". Если "like-a". Т.е., если эта штука похожа на чемодан и имеет ручку, то я возьму его и отнесу. И мне не нужно при проектировании плодить сущности "багаж"-"ручная кладь"-"чего-то-там". И если я на самом деле имею дело с портфелем или дипломатом, то мне без разницы, состоит ли он в каких-то родственных оношениях с чемоданом или авоськой.
D>С этой мыслью, я не спорю, но она imho к вопросу отношния не имеет. Скорее к вопросу, какие парадигмы есть возможность сделать mainstream.
Так и я о том, что не станет ли duck typing мейнстримом.
E>>Может быть ООП уже исчерпала себя (как в свое время структурное программирование) и сейчас мы наблюдаем за возникновением новой парадигмы?
D>"Утиные истории" появились задолго до ОО, например тот же Lisp.
Да, но особенности Lisp-а и Smalltalk-а не позволили им набрать большого количества сторонников. А вот Python и Ruby популярность набирают.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Это почему? Где-то потоком будет файл. Где-то строка. Где-то сокет. E>Или вокруг этого какие-то обертки, реализующие некоторый интерфейс строить придется?
Совершенно верно. Потому что требовать от, скажем, строки поддержки метода Read() как-то странно.
В стандартную библиотеку FCL входят и NetworkStream и FileStream.
StringStream нету, потому что поток — это байты, а строка — это символы. Аналогом является MemoryStream.
Для работы с текстовыми данными есть отдельные классы TextReader и TextWriter.
E>CanSeek -- это метод интерфейса Stream? Абстрактного класса Stream.
... << RSDN@Home 1.1.4 stable rev. 510>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, eao197, Вы писали:
E>А я про типизацию-то в данной фразе и не говорил. Я имел в виду, что в ООП мы используем отношение "is-a" для определения взаимосвязи между сущностями. Отсюда и необходимость выстраивать иерархии наследования. А если брать duck typing, то наследование здесь вообще пофигу, нет никакого "is-a". Если "like-a". Т.е., если эта штука похожа на чемодан и имеет ручку, то я возьму его и отнесу. И мне не нужно при проектировании плодить сущности "багаж"-"ручная кладь"-"чего-то-там". И если я на самом деле имею дело с портфелем или дипломатом, то мне без разницы, состоит ли он в каких-то родственных оношениях с чемоданом или авоськой.
Ну не используется is-a в ООП. Is-a появляется вместе с типами (классами). Вот рассмотрим два варианта: объект используем и объект имплементим.
Когда искользуем, то посылаем ему сообщение, и тут совершенно не важно is-чего-он-там. Важно, что он объект, и послать можно. Тут скорее речь о responds-to. Вот это действительно интересно. В статически типизированых языках тип объекта дает ответ на этот вопрос. В димамически — может дать ответ класс, но не обязательно. В Smalltalk класс может дать только положительный ответ, а отрицательный — не может (см. _vovin вчера подробно про doesNotUnderstand: написал). Is-a это важно компилятору, например, C++. Если объект типа MyClass то сообщени foo() посылается через 5ю запись в vtbl.
Теперь про имплементим. Тут надо написать как объект реагирует на сообщения. Возьмем Self или JavaScript. Никакого is-a. Хватаешь объект и давай ему добавлять/удалять поведение. Опять приходим к response-to.
Но если используем типы (классы), то появляется возможность добавить поведение отнаследовав его от другого класса. Так же тут появляется необходимость в объявлении поддерживаемых наборов сообщений (протоколов, интерфейсов, или как это еще кто назвал). А нужно это только для системы типов, что бы с ее помощью проверить код, или сделать какие-то выводы, но сама идея ОО тут ни при чем.
В твоем примере, что бы таскать багаж типы действительно не нужны. И грузчику ты действительно скажешь "беги за ручку и неси туда". А вот что бы такую процедуру записать на статически типизированном языке тебе понадобится тип "ШтукаСРучкой".
D>>С этой мыслью, я не спорю, но она imho к вопросу отношния не имеет. Скорее к вопросу, какие парадигмы есть возможность сделать mainstream.
E>Так и я о том, что не станет ли duck typing мейнстримом.
Ну от чего же? А VB, особенно VBA, VBscript? Опять же JavaScript? А если еще C#3.0 выйдет?
D>>"Утиные истории" появились задолго до ОО, например тот же Lisp.
E>Да, но особенности Lisp-а и Smalltalk-а не позволили им набрать большого количества сторонников. А вот Python и Ruby популярность набирают.
Я про Lisp написал, как еще один аргумент, что ОО — концепция ортогональная.
Здравствуйте, eao197, Вы писали:
E>Есть небольшое отличие: динамические языки проще адаптировать к некоторым условиям. Например, нужно прочитать из потока заголовок, определить, сколько байт нужно пропустить, а затем прочитать еще несколько байт. Если потоком является файл, то можно просто сделать seek, а если потоком является сокет, то пропускаемые данные нужно читать: E>
Уникально мерзопакостный вариант
Для читателя кода — stream.respond_to( "seek" ) — выглядит как грязный хак.
Код должен (в идеале, естественно) читаться как постановка задачи.
С этой точки зрения, финальный вариант на C++
E>template< class T >
E>void load_header_and_data( T & stream )
E>{
E> Header h = load_header( stream );
E> seek( stream, h.get_length() );
E> load_data( stream );
E>}
E>
...читается существенно лучше. Другое дело, что для этого тебе потребовалось неимоверное количество усилий. Однако же. Ты реализовывал не свою постановку задачи "Если потоком является файл, то можно просто сделать seek, а если потоком является сокет", а другую постановку задачи "если у объекта, каким бы он ни был, есть метод seek, то..."
Наиболее изящным решением на C++ было бы — либо А:
template<typename T> seek(T,int);
template<> seek<File>(File _f, int _bytes);
template<> seek<Soket>(Soket _s, int _bytes);
либо Б:
class File
{
...
void skip(int _bytes){seek(_bytes);}
...
}
class Socket
{
...
void skip(int _bytes){read(_bytes);}
...
}
А твое решение (как на Руби, так и на С++) совершенно нерасширяемо — завтра у тебя появится еще один тип потока, у которого надо будет вызвать вообще функцию, скажем, move, и что?
def load_header_and_data( stream )
h = load_header( stream )
if stream.respond_to( "seek" )
stream.seek( h.get_length() )
else if stream.respond_to( "move" ) //и такие хаки - еще в 18 местах...
stream.move( h.get_length() )
else
stream.read( h.get_length() )
end
load_data( stream )
end