По факту защиты мной диплома образовалось некоторое свободное время и я таки решил собраться и написать про эту чудесную штучку.
Мы в последнее время видим всплеск интереса ко всяким языкам очень высокого уровня, с анонимными функциями, каррингом, мапом/фолдом, метапрограммированием и прочим блэкджэком. Слава богу, я считаю.
Задачи усложняются и если люди применяют относительно низкоуровневые средства разработки зачастую наступает ситуация, когда набор абстракций оказывается мал в рамках решаемой задачи, примерно так появляется «спагетти» и велосипеды. Хорошего мало. Хотя умалять роль низкоуровневого программирования не хочется совершенно, по понятным причинам.
Совсем недавно, в 2002 году, бравый американец
Стив Декорте понял, что ему как-то все вокруг не нравится. Ну то есть нравится, но как-то по частям. Нравится Smalltalk своей Ъ-ООП природой, нравится Lisp своей системой метапрограммирования и общей мегаизвратностью, нравится Self своими прототипами, нравится Lua, потому что маленькая и клево встраивается куда угодно. А вот что бы все и сразу — что-то не то. Погоревал бравый американец, да и наколбасил свой собственный язык программирования — Io.
Io
Io это маленький, полностью объектно-ориентированный язык программирования с динамической типизацией и развитой системой метапрограммирования, анонимными функциями и вытекающими отсюда плюшками. Кроме того, Io невероятно прост, как в синтаксисе, так и внутри. Существуют всего две сущности: объекты и сообщения. На этом базисе построено все остальное. Вообще весь язык следует дзенскому духу минимализма и простоты.
В Io нет понятия класс, только объект. Объект может быть склонирован и изменен, таким образом мы получаем другой объект (Это и есть прототипы). Все типы данных, значения и прочая — объекты.
Ну что, поехали.
Io в примерах
"Hello world" print
Это самизнаетечто. Многих (да и меня в самом начале моих платонических отношений с Io) сильно смутило, какого хрена так странно вызывается print? Тут все просто, главно понять, что в Io нет методов и свойств, есть слоты и сообщения. В данном примере строке "Hello world" отправляется сообщение print. В более традиционных ООП языках это будет выглядеть примерно так:
"Hello world".print()
Это что бы было проще понять.
Теперь непосредственно про хваленое прототипное ООП:
Mushroom := Object clone
Mushroom isPoison := false
Mushroom whenEaten := method(person,
if(self isPoison == true,
person kill
)
)
В этом фрагменте кода мы создаем объект Mushroom, определяем его как съедобный и создаем метод whenEaten убивающий съевшего в случае, если гриб оказался ядовитым.
Man := Object clone
Man state := "Living"
Man eat := method(food,
food whenEaten(self)
)
Man kill := method(
self state := "Dead"
)
Определяем объект «Мужыг», как видно из кода, Мужыг можеть есть и умереть (ну вот как-то так).
Как доказал Сергей Анатольевич Курёхин — Ленин был грибом. Таким образом мы можем определить ленина через клонирование класса Mushroom:
Lenin := Mushroom clone
Lenin isPoison := false
Lenin speak := method(
"Патриотизм - одно из наиболее глубоких чувств,
закрепленных веками и тысячелетиями обособленных отечеств." println
)
Так же, для разнообразия, можно определить ядовитый гриб:
InfectedMushroom := Mushroom clone
InfectedMushroom isPoison := true
Теперь мы можем попробовать накормить мужика чем-нибудь:
Man eat(Mushroom)
Man state println
Напечатает «Living».
Man eat(InfectedMushroom)
Man state println
Соответственно «Dead»
В то время, пока Ленин говорил:
Lenin speak
Пришел мужик съел его:
Man eat(Lenin)
И остался жив.
Метапрограммирование
Система метапрограммирования в Io в тысячу раз проще чем в том же Lisp'е, но не менее мощная. Здесь нет понятия «макрос», тут просто все дерево кода доступно в рантайме. Не надо извращений со сложными синтаксическими конструкциями, просто изменяй код «on fly» как тебе захочется.
Мой любимый пример — реализация Singleton'а в Io:
Singleton := Object clone
Singleton clone := Singleton
Тут я просто переопределил стандартный метод clone, что бы он возвращал тот же объект.
Напоследок
Io очень молодой, но не по годам прикольный язык. Несмотря на его мегаизвратность и мощность он крайне простой. Сам язык расчитан на легкость встраивания в чужеродные системы, к нему легко писать модули на низкоуровневых языках, когда требуется перфоманс. Для него уже сейчас написано достаточно библиотек.
Существуют несколько проектов, активно использующих Io, например проект
It — скриптовый язык основанный на Io, разработанный в Pixar.
Сейчас я занимаюсь переводом документации по Io на русский язык. Конечно, я затронул очень мало в этом посте, так что продолжение следует (-;
Ссылки
http://iolanguage.com
(Из моего
блога)
upd: продолжение цикла:
Синтаксис Io
комментарии (135)
Как раз хотел присмотреться к какому-нибудь неизвестному мне языку программирования, для повышения профессионального уровня. Похоже, этим языком программирования будет Io.
Вот только есть предложение не хвататься за Io, а схватиться за Lisp, например.
В Io желательно приходить уже зная, что могут дать метапрограммирование, лямбда-функции и прочее. К тому же пока по Io очень мало толковой документации, но мы работаем над этим (:
Правда, с Lisp'ом я знакомился один семестр на третьем курсе, и воспоминания не слишком приятные :)
Почитайте «On Lisp» Грэма или «Practical Common Lisp». Ну и «SICP», конечно.
Хотя да, рубистам в Io будет приятно и легко.
А если одним словом, все хорошо расписано в книжке «Структура и интерпретация компьютерных программ». Она вышла у нас на русском и есть в pdf в интернетах.
Ща задефуню.
Видео лекции. Сам смотрю сейчас. :)
В общем-то в Io любое сообщение method — лямбда функция. Есть еще block, который еще более лямбда-функция, но про него я как-нибудь в следующий раз.
это что-то вроде typedef int (*PFUNC) (int);
?
В данном случае их можно заменить на blockquote
Из фишек на затравку, Io умеет:
Классов-то нет.
И чем по-вашему метод «отличается» от «сообщения», а «свойство» от «слота»? По-моему ничем, если учесть что «метод — кусок кода, ассоциированный с объектом или классом».
Больше всего это напоминает мне JavaScript со стейтментами в стиле лисп (с лиспом не знаком).
А про отличия: слот --- абстрактный контейней, который может содержать как значение, так и «метод». Все это в общем случае --- сообщения.
____
интересно, как в более-менее сложном коде предполагается создать два объекта одного типа в разных местах (где клонирование недоступно)… предполагаю, будет уже не так красиво
function Human(name, age, city) {
this.name = name
// что-нить сложное
}
fuction one() { new Human("Elsa", 19, "Hamburg") }
fuction two() { new Human("Egor", 32, "spb") }
Как в данном случае обойтись одним клонированием, мне не оч. понятно… Т. е. извернуться можно, но красиво пока не входит.
А мне кажется, что объект - это экземпляр класса. Класс — это тип, описывающий устройство объектов — экземпляров.
Вот конкретно в модуле Directory под винду есть косяки с юникодом, но только в этом модуле и только под винду.
просто у меня есть ощущение, что юникод не очень хорошо сочетается с маленькими встраиваемыми языками — там сложностей вроде бы много
да и пример работы со строкой, где по индексу возвращается число, а не символ, тоже усилил подозрения
Строка в Io это объект наследуемый от Sequence, со всеми вытекающими map/fold и итераторами.
даешь еще статей по ИО
Жаргон, фигли, а так можно конечно.
Вот тут что-то совсем нерадостно.
И это при условии, что MRI (Ruby 1.8) сам по себе достаточно медленный.
А вообще язык симпатичный.
> Совсем недавно, в 2002 году,
это всё было давно опубликовано в 1969 году в спецификации на forth
на лиспе тоже можно реализовать что угодно. Кроме того у ТруЪ-ООП есть всего одно мерило --- smalltalk.
а в смалтолк, хотя и замечательный ооп, но тоже не идеален. например, в нём нет интерфейсов, нет локальной перегрузки стандартных типов. ну и больше всего убивает - ориентированность на то, что пользователь работающий с программой и разработчик оной - одно лицо.
Я так и не понял, в чем его ценность.
принт куда? возможность "печатать" - это свойство принтера, а не бумаги.
лучше бы сделали так:
con.print( "Hello world" )
при этом метод print должен вызывать "Hello world".toString
это с точки зрения ооп.
с точки зрения синтаксиса, лучше подход цпп:
con все дерево кода доступно в рантайме
только не вздумайте его менять, иначе замучаетесь с отладкой.
два различных синтаксиса вызова методов (со скобочками и без) - это очень плохо.
есть ли возможность перегружать присваивания? например, когда я хочу генерировать ошибку при попытке изменения какого-либо слота (ридонли свойство).
цпп код: console
ну и далее у меня было написано что-то про то, что все эти новомодные языки по сути своей ущербны, ибо на них нельзя написать ядро ос и другие рилтайм приложения. для эффективного использования ресурсов остаются только цпп и ада. печально всё это =(
но это не самое главное. фишка в том, что потоковая обработка - это халява для функциональных языков. их бич - активная работа с памятью. например, наложение фильтров на изображение.
и не надо судить о многочности в императивных языках по одному лишь цпп, который до недавнего времени её вообще не поддерживал. в языке ада, например, с многопоточностью всё в порядке.
вообще, довольно глупо тянуть чисто математическую абстракцию на чисто императивную архитектуру компьютера. всё-равно интерпретатору приходится конвертировать функциональную программу к императивной форме.
особенно убивает реализация естественных для человека циклов через рекурсию и дальнейшие шаманства с "хвостовой оптимизацией"...
а вот винрар - да, хотя и быстрее обоих, но жмёт хуже.
проблемы начинаются, когда нужно совместить несколько задач в одном приложении. тут и получается тормозящая химера.
не надо путать декларативные языки с функциональными. на чисто функциональном языке, например, невозможо сделать простой чекбокс на форме. чтобы изменить его состояние, нужно отправить всё окно на съедение автоматическому сборщику мусора и с нуля сгенерировать новое, но с другим состоянием чекбокса.
по этой причине чистый функциональный подход нигде и не применяется - только для отдельных вычислительных тасков.
в то же время декларативный подход вполне допускает динамическое изменение состояния.
например: <a href="javascript:this.innerHTML='yes'">no</a>
не надо судить об императивном программировании лишь по одному убогому, но крайне популярному представителю.
там, где программисты просто используют цикл - там уже нет ФП. это самый обычный императивный язык с функциями, где программа из проского списка комманд переписана через последовательность вызова этих самых функций.
2. наоборот. ртфм.
3. и что, каждый раз при изменении окна разворачивать по новой?
4. конкретные языки назови.
5. кроме сипипи
То-то я смотрю у нас вся математик в циклах! Для человека циклы настолько же неестественны как и рекурсия, вощемто.
А рекурсия намного более выразительно в большинстве случаев. И довольно глупо тащить на процессор языки отличные от машинных комманд, все равно ведь компилятор их туда развернет.
он сразу поймёт, что энфакториал - это произведение всех чисел от 1 до эн.
однако в математическую формулировку: n!= n ? n*(n-1)! : 1 - ещё придётся повъезжать, раскладывая мысленно в указанный выше ряд
затем, что в мой ноут больше гига не всунуть, а есть платформы в которых памяти и того меньше.
затем, что мне нужно тестировать свои программы в десяти различных средах и из-за их прожорливости приходится останавливать одну виртуальную машину, чтобы запустить другую.
затем, что на гигабайт usb-диска я лучше залью сотню-другую песен и буду наслаждаться разнообразием репертуара в дороге.
l4 - это ядро, написанное на цпп. под ним запускается iovm - виртуальная машина ио, написанная на си. и уже под ней - приложения, написанные на io.
активных имплементаций всего четыре. 3 из них на цпп, одна - на си. iol4 использует первую - Pistachio.
на цпп я не программировал уже лет пять. и совершенно не хочу к нему возвращаться. но и новые веяния не слишком радуют...
ещё вопросы?
http://vkontakte.ru/club3618361