Бертранд Мейер рассказал в своем блоге о новой конструкции across в языке Eiffel, которая выполняет роль цикла foreach, но не только.
Вот так теперь может записываться обход всех элементов контейнера:
across s as c loop print (c.item) end
А вот так подсчет суммы всех элементов контейнера:
across s as c from sum := 0 loop sum := sum + c.index * c.item end
Раньше нужно было писать так:
from
sum := 0 ; s.start
until
s.after
loop
sum := sum + s.index * s.item
s.forth
end
В качестве s может использоваться объект любого класса наследника ITERABLE. В качестве c будет использоваться объект того типа, который возвращает метод new_cursor объекта s. По умолчанию это тип ITERATION_CURSOR, но конкретный контейнер может использовать и наследников от этого класса.
Вот так можно обойти контейнер в обратном порядке:
across s.new_cursor.reversed as c loop print (c.item) end
Мейер говорит, что в Eiffel встраивается некоторая защита от модификации контейнера, по которому идет итерация посредством across. В этой защите каким-то образом задействовано постусловие и новое свойство контейнеров is_valid. Вроде бы, когда контейнер модифицируется, его свойство is_valid возвращает false вместо true и это останавливает цикл. Но как это реально работает я не понял, а сама новая версия библиотеки EiffelBase с поддержкой is_valid еще не готова.
Однако, самое интересное в across то, что эта конструкция может использоваться не только в качестве цикла, но и в качестве предиката. Например, выражение:
across s as c all c.item > 0 end
будет истинным только если все элементы контейнера s больше нуля. А выражение:
across s as c some c.item > 0 end
будет истинным если хотя бы один элемент контейнера s больше нуля.
Забавный все-таки язык Eiffel. И развивается забавно.
12 комментариев:
А раньше итераторов в Эйфеле не было?
Вообще напоминает питон, там итерируется все что шевелится.
Когда я изучал Eiffel 2.5 года назад, я не нашел там итераторов, похожих на STL-евские или таких же удобных средств обхода содержимого контейнеров, как for_each, for_each_with_index, map, inject из Ruby.
Помнится, там для каждого типа контейнера был собственный способ обхода.
Но, поскольку на Eiffel я мало программировал, то могу ошибаться.
Впрочем, я чуть наврал. Оказывается, тогда уже был в классе LIST метод do_all, который принимал агента (т.е. замыкание). Но широко использовались и итерации "старым" способом (см.здесь в конце раздела пример).
Упс, неправильный URL, вот правильный: http://eao197.narod.ru/better_language/languages/eiffel/1_my_impressions.html#command-query
Да Эйфель тоже не такой продуманный как рекламируются :)
По уму в хорошем императивном языке итераторы необходимы, тем более "прототип" такого языка давно существует http://en.wikipedia.org/wiki/CLU_(programming_language)
>Да Эйфель тоже не такой продуманный как рекламируются :)
Есть такое дело. Причем горячие приверженцы "церкви Eiffel" готовы сжечь всех несогласных на костре :)
Вот а тут некоторые говорят что функциональщики злые :)
Функциональщиков больше и они кричат сильнее. Eiffel-исты же просто и бесповоротно уверены в своем превосходстве :)
У Eiffel есть как минимум два серьезных недостатка:
1) Отсутствие пространств имен. Говорят, даже в библиотеках самой EiffelStudio встречаются префиксы в именах классов (!)
2) Огромный объем файлов, генерируемых в отладочном режиме. Да и вообще, Eiffel не слишком экономно память расходует. Видимо перемудрили с трансляцией в си.
Более подробно об этих и других проблемах можно почитать в списке рассылки:
1) http://n2.nabble.com/Re-Eiffel-popularity-namespaces-td4460493.html#a4460493
2) http://n2.nabble.com/Eiffel-popularity-td4428765.html#a4428765
>1) Отсутствие пространств имен. Говорят, даже в библиотеках самой EiffelStudio встречаются префиксы в именах классов (!)
Почему же "говорят"? Так и есть: http://doc.eiffel.com/static/libraries/base/ -- вот классы с префиксами RT_, SED_. А в Gobo (который сейчас, похоже, включают сразу в EiffelStudio) так вааще: http://doc.eiffel.com/static/libraries/gobo/index.html
>Огромный объем файлов, генерируемых в отладочном режиме.
Не столько в отладочном, сколько с полной поддержкой DbC (включая инварианты циклов). Тогда да, даже маленькая программа будет весить десятки мегабайт. Но в Eiffel этим делом можно гибко управлять. Даже можно задавать уровень DbC для отдельных кластеров.
>Да и вообще, Eiffel не слишком экономно память расходует.
Как-то не заметил. Обычный расход для языка с GC. На некоторых тестах даже шустрее работает и меньше памяти жрет, чем C++ (кажется, такое проявлялось на memory_trees из Language Shootout-а).
Недавно я спросил в упомянутом мной списке рассылки: что плохого в пространствах имен? После этого вопроса там разгорелась бурная дискуссия. Вот что ответил на этот вопрос сам Бертран Мейер:
As to namespaces: personally I have no particular hostility to the idea, but one of the criticisms I have heard from large-scale users (who,
understandably, have considerable influence over what happens with the language), is that they make refactoring difficult. If you start referring to classes in terms of their namespaces, it becomes much harder to move them
around.
2Quaker: странный аргумент. Что-то не видно, чтобы в Java или в C# система пакетов/пространств имен препятствовала рефакторингам. Там вообще автоматический рефакторинг силен как нигде.
Подобные вещи, может быть, гораздо сложнее в C++ с его шаблонами и макросами. Но ведь не на C++ же здесь нужно ориентироваться.
Отправить комментарий