PDA

Просмотр полной версии : Циклы для профи


elder_Nosferatu
10.03.2013, 01:19
Салют!

Периодически просматривал исходники движков или просто чужих приложений и заметил одну особенность - чем больше мне нравится стройность кода и алгоритмов (для меня это один из признаков проффесионализма), тем реже в таких исходниках встречается слово "for".
Возник вопрос: "Почему умные люди отказываются от такой удобной конструкции, как цикл FOR?" ("FOR-IN" это не касается)
Когда я задал этот вопрос себе, то ничего из этого не вышло - похвастаться хорошими познаниями в программировании я не могу даже перед собой. Полез в Гугол, но там не нашел ничего внятнее, чем тесты, результаты которых не дают большой разницы.

Искать ответ мне надоело и я просто решыл отучиться от цикла FOR. Я даже нашел в этом позитив - когда нет разници в порядке обхода элементов массива я всегда делаю обратный обход:
красивый и компактный вариант
var i:int = arr.length;
while (i--) {
// очень много строк кода с элементом arr[i]
}
против громоздкого
var len:int = arr.length;
var i:int = 0;
while (i < len) {
// очень много строк кода с элементом arr[i]
i++;
}
Все было бы класс, но когда приходится делать прямой обход элементов, я, иногда, забываю модифицировать счетчик цикла, что приводит к зависанию приложения. Найти и устранить такие ошибки очень легко, но частота их появлений очень мешает.

И сегодня меня волнует новый вопрос: "А стоило переходитm с цикла FOR на цикл WHILE?"
Есть ли у кого нибуть умные мысли по этому поводу?

Astraport
10.03.2013, 01:42
для меня это один из признаков проффесионализма
:)

А вообще не всегда for можно заменить на while, по быстродействию они идентичны.

iflamberg
10.03.2013, 02:03
Все очень просто.
Просто вот эта конструкция:

var i:int = arr.length;
while (i--) {
}

быстрее чем:

for (var i:int =0; i<arr.length;i++){
}

Потому что arr.length - медленный.

elder_Nosferatu
10.03.2013, 02:37
А вообще не всегда for можно заменить на while.

А можно пример? Немогу даже представить такой ситуации.



for (var i:int =0; i<arr.length;i++){
}




var len:uint = arr.length;
for (var i:int = 0; i < len; i++){
}

И все в порядке. Как только начал писать свои get/set-методы сразу понял, что в цикле легче работать с переменной чем с get-функцией length.

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

Может кто нибуть высказаться в пользу цикла while?

Zebestov
10.03.2013, 02:41
...когда приходится делать прямой обход элементов, я, иногда, забываю модифицировать счетчик цикла...
Просто не забывай.

Потому что arr.length - медленный.
Поэтому перед циклом длину в переменную сохраняют.

Sync
10.03.2013, 02:54
for - быстрее. он на 1 инструкцию короче, чем while --i, можно убедиться декомпиляцией тестов, если речь пошла о таких сравнениях

caseyryan
10.03.2013, 10:54
А вообще не всегда for можно заменить на while, по быстродействию они идентичны.
цикл for, всегда можно заменить на while. Если не писать это вручную, то компилятор все равно это сделает.
вот for in или for each in нельзя, но это уже другое
И все же не понятно, почему люди отказываются от удобной конструкции, если разници нет?
Скорее всего просто для того, чтобы код было удобнее читать, ну и писать. Ведь он короче.

alatar
10.03.2013, 14:03
когда нет разници в порядке обхода элементов массива я всегда делаю обратный обход
Когда нет разницы можно и Array#forEach использовать.

alexcon314
10.03.2013, 14:20
Гле-то читал в литературе примерно следующее субъективное мнение.
Когда программирование стало доступным? Да, с приходом Basic. Его стали преподавать везде и всюду. Цикл FOR для бейсика - это своего рода завоевание (не во всех языках эта конструкция поддерживалась изначально), все, кто изучал программирование на Basic - всегда пишут FOR, их даже узнать легко по этой фишке.
Но реальные пацаны выше этих яслей, они юзают кондовый WHILE. :)

alatar
10.03.2013, 14:29
Что-то я не припомню в бейсике (если мы не о Visual Basic) цикла FOR, да и вообще циклов, кроме GOTO X вроде не было. В паскале были.

Zebestov
10.03.2013, 14:32
Ну как же!

FOR I = 1 TO 100 STEP 10
...
NEXT

Лихие 90-е, MSX Basic.

alexcon314
10.03.2013, 14:37
Да не.. были же и FOR и WHILE и GOTO.

alatar
10.03.2013, 14:38
Значит запамятовал уже. :)

Tails
10.03.2013, 14:51
Нет циклов, операторов, etc для - "проффи", есть грамотно написанный код.

alatar
10.03.2013, 14:51
Лихие 90-е, MSX Basic.
У нас GW-BASIC был. С robotron вроде он поставлялся.

Zebestov
10.03.2013, 15:07
Ага. У нас просто класс был укомплектован компьютерами YAMAHA КУВТ, так что мое детство прошло под стягом MSX ))

expl
10.03.2013, 15:54
Но реальные пацаны выше этих яслей, они юзают кондовый WHILE
В C# еще есть разница между этими циклами - там переменная i обявленная в for (int i = ... будет доступна только внутри цикла. А внутри while(...) её тупо не объявишь.
А в as3 этого нет :(. Поэтому нет и никакой разницы между этими циклами. И по производительности тоже.
И не знаю чем обдолбился автор этих строк, что решил мерить пофессионализм частотой использования цикла while.

Единственная причина, по которой используют for - это экономия строчек, т.к. по кодостайлу так писать нельзя, да и не выглядит красиво:

var i:int = 0; while(i < 10)
{
...
i++;}

А так можно:

for (var i:int = 0; i < 10; i++)
{
...
}

Вот и всё. При чём здесь BASIC не понятно.

А для сложных случаев самый удобный цикл - это while(true). Ну с while(condition) надо мозги напрягать, чтобы ничего не продублировать и вообще правильно собрать,
а для while(true) такой сложной мыслительной деятельности не требуется - содишь условия по месту и всё:

while(true)
{
...// то что в любом случае сделаем, даже если условие не выполнено
if (!condition) break;
...// то что только при выполнении условия
if (condition2) break;// а тут по другим причинам мы не можем продолжить
if (condition3) continue;// а блок дальше нам в этом случае не нужен
...
}

Дёшево и сердито

Sintesis
10.03.2013, 16:34
вот такой цикл вроде должен работать быстрее всех:

var i:int = myArray.length;
while (--i > -1)
{
}

в документах Adobe пишут:
Используйте обратный порядок для циклов while.
В обратном порядке циклы while выполняются быстрее, чем в прямом.
Да и вообще можно взять и прямо в коде потестировать таймером оба цикла и for и while.
Хотя это уже много раз тестировалось получается так: циклы по скорости в порядке убывания while, for, foreach, for..in

chamele0n
10.03.2013, 18:36
обратный порядок быстрее
просто не многие застали ассемблер и не знают что такое стек и структура лифо (Last In, First Out)

gloomyBrain
10.03.2013, 19:06
обратный порядок быстрее
просто не многие застали ассемблер и не знают что такое стек и структура лифо (Last In, First Out)

Я все же полагаю, что способ написания цикла на AS3, скажем, не всегда связан со способом его исполнения в AVM2. Иначе говоря, утверждение о скорости выполнения циклов в AS3 вряд ли можно связывать с реалиями ассемблера. При чем тут LIFO, чесно говоря, не совсем ясно.

mikhailk
10.03.2013, 19:36
обратный порядок быстрее
просто не многие застали ассемблер и не знают что такое стек и структура лифо (Last In, First Out)

Обратный порядок быстрее, потому что длина массива вычисляется один раз в начале цикла, а потом текущее значение переменной сравнивается с -1. Другой причины я что-то не вижу.
А если длину массива считать до начала цикла, то и разницы никакой не будет.

Sync
10.03.2013, 19:45
обратный порядок быстрее
просто не многие застали ассемблер и не знают что такое стек и структура лифо (Last In, First Out)
в ассемблере тоже нет такой структуры. есть просто стек.
как можно не застать асм, если мы все сидим за компами.
обратный цикл в асме был быстрее по такой простой причине, что операция вычитания выставляла в регистре флаг нуля, и операция сравнения перед условным переходом не требовалась, что экономило несколько тактов.
Регистровой модели я в AVM не нашел. кините ссылку?
Более того, (для AVM) в цикле for (поскольку его можно просто и понятно оптимизировать) инкремент\декремент происходит без помещения переменной в стек, а в while приходиться изымать переменную, уменьшать её, помещать обратно, снова изымать и производить сравнение. Время выполнения операций я не нашел, но по факту в тестах for лидировал.
ЗЫ. Тоже считаю странным сравнивать программеров по циклам. Ещё бы количество точек в тексте считали.

elder_Nosferatu
10.03.2013, 22:23
И не знаю чем обдолбился автор этих строк, что решил мерить пофессионализм частотой использования цикла while.


ЗЫ. Тоже считаю странным сравнивать программеров по циклам. Ещё бы количество точек в тексте считали.

Не так уж и внимательно вы читали мой пост. Для меня одним из признаков профессионализма есть "стройность кода и алгоритмов". А частота использования цикла while просто бросилась в глаза. Вот и стало интересно - есть ли в этом что нибуть существенное или просто сила привычки.

Добавлено через 3 минуты
К стати, так и не увидел ни одного примера, когда нельзя заменить цикл for на while
А вообще не всегда for можно заменить на while

Astraport
10.03.2013, 23:20
К стати, так и не увидел ни одного примера, когда нельзя заменить цикл for на while
Мне казалось, что когда-то в такой же дискуссии был такой пример.

Это не замена: например мне нужно перебрать массив именно с начала, но не с первого а n-го элемента, то по количеству строк while уже проигрывает.

mikhailk
10.03.2013, 23:37
К стати, так и не увидел ни одного примера, когда нельзя заменить цикл for на while

Такого примера не существует по определению. Любой цикл for можно представить в виде while, причем достаточно тривиально. Вот наоборот естественным образом не всегда.

Например:


while(container.numChildren>0)
{
container.removeChildAt(0);
}


Конечно, и его можно записать в виде for (надо в теле цикла сбрасывать переменную в ноль), но наглядность потеряется да и с точки зрения логики странновато.

Wolsh
11.03.2013, 00:08
for(var i:uint = container.numChildren; i > 0; i--)
{
container.removeChildAt(0);
}Что тут странного?

Добавлено через 12 минут
Можно же вообще без инкремента обойтись
for(; container.numChildren > 0;)
{
container.removeChildAt(0);
}

mikhailk
11.03.2013, 00:20
А только мне кажется такой цикл абсурдным? :)

Нет, можно и вот так:

var childCount:uint = container.numChildren;
for(var i:uint = 0; i < childCount; i++)
{
container.removeChildAt(0);
}


Какими-то костылями попахивает?

expl
11.03.2013, 00:21
Не так уж и внимательно вы читали мой пост. Для меня одним из признаков профессионализма есть "стройность кода и алгоритмов". А частота использования цикла while просто бросилась в глаза. Вот и стало интересно - есть ли в этом что нибуть существенное или просто сила привычки.
А вот то, что про BASIC и отвыкание от for было написано - это ваши слова? Я думал это из блога какого-то чела цитата выдрана. И не мог не заметить, что не стоит верить этому товарищу.
К стати, так и не увидел ни одного примера, когда нельзя заменить цикл for на while
Да они одинаковые, что while, что for - просто синтаксис другой (если for (each) in не брать) - они _не_ могут быть _не_ взаимозаменимими.

Если вернуться к исходному вопросу:
"А стоило переходитm с цикла FOR на цикл WHILE?"
Вот и haXe выпилили for, оставили for in. Оно конечно, писать то можно и проблем не возникает, но иногда бесит писать 3 строчки вместо одной.
Вобщем, зря Вы переключились на один вид цикла - лучше и то и другое использовать.

Кое-где видел, что пишут for (; condition; ) {...} вместо while - видимо под лозунгом "Безобразно - зато однообразно".
Тенденции отказываться от for я не замечал - от этого нет никаких выгод (Николя только отличился, и никому это не нравится). Большинство использует и for и while - по ситуации.

elder_Nosferatu
11.03.2013, 00:34
А вот то, что про BASIC и отвыкание от for было написано - это ваши слова?

На счет отвыкания - это правда, через это я прошел самостоятельно, хотя и небыло большой проблемы в этом. А вот про BASIC я ни словом не заикнулся. Лично я к ниму отношусь "не очень". Еще в школьные времена, после ознакомления с Turbo Pascal, я решил посмотреть на BASIC и ужаснулся :(

Wolsh
11.03.2013, 00:37
А только мне кажется такой цикл абсурдным?
Какими-то костылями попахивает?Я лишь попытался показать Вам, что while и for абсолютно идентичны. Синтаксис for всего-лишь позволяет записать инкремент в "шапку" цикла, чтобы не искать потом по всему телу цикла, что там и как изменяется, и не искать до тела цикла создание переменной инкремента. Это просто удобная подробная запись. Которая может и не быть подробной, если этого не требуется. Вы можете оставить в for только condition, и все остальное оформить в точности как while.
Вот и вся разница.

expl
11.03.2013, 00:46
На счет отвыкания - это правда, через это я прошел самостоятельно
Отвыкания от FOR BASICа?
Всмысле поменять это:
FOR I = 0 TO 9
На это:
for(i = 0; i < 10; i++)
Ну да, авторы сишного синтаксиса посчитали цикл, где явно задаётся диапазон излишеством.
Но дальше то зачем идти именять это на while?
Ведь то же самое - один в один. Сишный for - это while написанный по другому. Только при использовании while(там где подойдет for) получается больше строчек и читать тяжелее. Чего ради?

alexcon314
11.03.2013, 00:49
Как-то стало интересно, где ж я накопал про BASIC и FOR... и насколько точно изложил мысль автора.
Поискал, благо года три всего прошло... Оказалось вот что: попалась случайно книга на глаза
С. З. Свердлов. Языки программирования и методы трансляции.
В моем издании (Питер 2007 (http://www.piter.com/book.phtml?978546900378)) на стр. 61-62 нашел то, что пытался изложить по памяти. Выкладываю оригинал на всякий случай..
(ч1. "Языки и эволюция технологий программирования", гл. "Интерактивное программирование для всех", пар. "Бейсик" разд. "Популярность бейсика".)
Против FOR автор ничего не имеет, вот против Бейсика - да. Возможно, сплошное употребление FOR, как признак "бейсикового" прошлого, косвенно может служить оценке специалиста-программиста не в лучшую сторону. Другими словами, если учесть сноску-совет в конце, гармоничное употребление WHILE\FOR - признак достаточно хорошего уровня владения профессией. Так, видимо следует понимать.
В любом случае, это единственный источник на моей памяти, где хоть что-то сказано о "пользе и вреде" FOR.

mikhailk
11.03.2013, 00:56
Кстати, на самом деле синтаксис

for(i = 0; i < 10; i++)

- это частный случай. Синтаксис может быть более сложным, правда в реальной жизни я такого не видел, только в хэлпе:


for (i = 0, j = 0; i < 3 && j < 3; i++, j+=2)
{
trace("i = " + i + ", j = " + j);
}


Кстати, операторы цикла, аналогичные по смыслу "for" появились до бейсика.

Astraport
11.03.2013, 01:08
Вот, кстати, как пример mikhailk на while перевести?

Wolsh
11.03.2013, 01:12
var i:int = 0;
var j:int = 0;
while(i < 3 && j < 3)
{
trace("i = " + i + ", j = " + j);
i++;
j+=2;
}Я вообще затрудняюсь понять, что за мистику Вы пытаетесь найти в этом while?

Добавлено через 12 минут
Вот например TextFormat — одни создают экземпляр и сразу инициализируют свойства в конструкторе. Другие не передают в конструктор никаких параметров, а описывают их все уже после конструктора.
И здесь мне видится то же самое, не более. Иногда while оказывается короче и понятней, а иногда for гораздо приятней читать — всё в одном месте. И статистика использования здесь совсем не при чем. Она скорее показывает, что новички элементарно не в курсе, что существует while, и не использует его вообще, или использует с большой неуверенностью. Но никаких технических преимуществ в нем нет, и ставить вопрос типа "либо одно, либо другое" — бессмысленно.

Добавлено через 16 минут
А еще "профессионалам" иногда — платят за строчки)))

mikhailk
11.03.2013, 10:49
Я согласен, никакой мистики в while нет, конечно.

На мой скромный взгляд, для зацикливания процесса до момента выполнения некоего условия логичнее выглядит while, для упорядоченного обхода всех элементов некоторой коллекции, когда каждый элемент имеет жестко привязанный к нему индекс - for, а для обхода, когда порядок не имеет значения - for each (в AS3 - for in).

Кстати, видел неодноократно использование while в стиле "чисто поржать". Ну, например:

while(!JESUS_CHRIST_COMING)
{
doSomething();
if (isDone()) break;
}

expl
11.03.2013, 11:23
а для обхода, когда порядок не имеет значения - for each (в AS3 - for in).
For each сохраняет порядок для массива и вектора.
Поэтому использую его для обхода всегда, если не нужно знать индекс элемента.

cleptoman
11.03.2013, 12:32
ох и темка)
юзаю в основном for, потому что самому потом понятно что где и куда. (а может просто бейсик привычка ))
п.с. еще do..while не разобрали )

wvxvw
11.03.2013, 12:35
Нужно не забывать о том, что цикл - это маленький строительный блок, и то том, что когда вы сталкиваетесь с написанием больших програм, вы не хотите создавать их из несоизмеримо маленьких фрагментов - как правило, вы пишете компоненты, потом создаете из этих компонент логические группы и т.д. строете иерархии / гетерархии.
Поэтому вы можете часто встретить мнение, что вместо цикла лучше использовать функции высшего порядка, такие как например find-if, flatten, transpose и т.п. - потому, что эти функции - абстракции уже содержащие в себе итерационный примитив + надстройку обеспечивающую дополнительные возможности.
Другим, не менее сильным инструментов в этом плане являются макросы, которых к сожалению, нет в AS3, и не смотря, что в принципе, их можно было бы добавить, это на столько не традиционно для языка, что я никогда с этим не встречался. Но в языках, где макросы - обыденная вещь, их часто используют для создания разных видов циклов. Для примера такого макроса можно посмотреть сюда: http://common-lisp.net/project/iterate/doc/Don_0027t-Loop-Iterate.html
Такие макросы созданы для того, чтобы решать типичные задачи, которые вы бы решали в цикле, например, подсчет, аггрегацию, фильтрование, сопоставление элементов двух и более коллекций и т.п.
Интересной особенностью последнего является то, что появившаяся возможность создает новые прецеденты, которые бы вы вряд ли захотели использовать с типичным for циклом. Например, вполне типично для этого макроса мы можем обьявить несколько итераторов, и, в одном и том же цикле перебирать ключи хеш-таблици и элементы массива, - конструкция в принципе не возможная в AS3.
Кроме этого, научившись использовать такие макросы вы начинаете думать об итерации по-другому. Например, мне как-то понадобилось написать цикл, который бы перебирал элементы дерева - если бы вы делали это с использованием for - у вас на это ушло бы десяток, а может и больше строчек, но с макросом та же задача решается в одну строчку, типа:
(iterate (for i vertex-of some-tree)
(do-some-stuff with i))

mikhailk
11.03.2013, 12:54
For each сохраняет порядок для массива и вектора.
Поэтому использую его для обхода всегда, если не нужно знать индекс элемента.

Естественно, сохраняет. :)

Вот этого варианта нагляднее и проще обычный for (а не for in/while):


var array:Array = [ 1, 23, 4, 54, 3, 1, 55 ];
for(var i:int = 2; i < 4; i++) array[i] = i*333;

expl
11.03.2013, 14:15
Поэтому вы можете часто встретить мнение, что вместо цикла лучше использовать функции высшего порядка, такие как например find-if, flatten, transpose и т.п. - потому, что эти функции - абстракции уже содержащие в себе итерационный примитив + надстройку обеспечивающую дополнительные возможности.
Угу, хорошо, ...для С#, Ocaml, F#. Но никак не для ActionScript3, потому что:
- нет типизации функций,
- вызов функции непростительно дорог.
В сортировке только используется и то только потому, что копипастить алгоритм сортировки слишком дико. Но в особо критических местах именно не быстрый вызов функции заставляет делать свою реализацию сортировки.
В as3 я использовал функции высших порядков только для выбора наиболее подходящих значений/вариантов/объектов по критериям. Критерии были как раз функциями, передававшимися в алгоритм выборки. Но это использовалось только в AI, туториале. В основной логике такого не было - дорого потому что и не типизировано.

Да даже и в C# как-то стремно эти штуки использовать, мало ли как на производительности скажется, только когда без них код слишком страшным становится.


Вот этого варианта нагляднее и проще обычный for (а не for in/while):

var array:Array = [ 1, 23, 4, 54, 3, 1, 55 ];
for(var i:int = 2; i < 4; i++) array[i] = i*333;

Да, логично, Вы здесь индекс используете внутри цикла и было бы слегка странно гнать foreach-ем и итерировать внутри цикла i++ одновременно, сравнивать i и вызывать break.

in4core
11.03.2013, 14:26
Что вообще за пустотелый бред - мерить профессионализм циклами? это знатное трололо !!!

А вот какой из этих 2х примеров профессиональнее??! )))

private var count:int = 0;
.................................
if(count) trace("hello");

или
................................
if(count > 0) trace ("hello");

???

mikhailk
11.03.2013, 14:43
А вот какой из этих 2х примеров профессиональнее??! )))

Второй?

semenyakinVS
11.03.2013, 15:57
Зачем применительно к скриптовому языку обсуждают способы выиграть несколько команд процессора? По-моему, куда важнее читабельность кода. И for, по-моему, в этом смысле лучше подходит почти во всех случаях.

P.S.: Я могу ошибаться, но мой опыт работы с С++ подсказывает, что while (i--) стоит делать чуть чаще чем никогда (так же как использовать побитные команды для оптимизации всяких умножений и округлений). По-моему, не стоит, опираться на особенности представления числа в памяти при работе с ним. Представление может поменяться, может поменяться разрядность числа (опять-таки, вполне вероятно, что для скриптовых языков это не так актуально и я ошибаюсь, если что - поправте меня).
Плюс формально не логично - использовать число в качестве флага. Тут хоть декримент стоит и видно, что это число. А если бы было что-то вроде while(i) - вообще беда и путаница для программиста, читающего код.

А вот какой из этих 2х примеров профессиональнее??! )))

P.P.S.: Да, второй.

alatar
11.03.2013, 16:12
А я угадаю эту мелодию с двух нот. )
P.P.S.: Да, второй.
Откуда такой однозначный вывод?

in4core
11.03.2013, 16:13
Второй да, ну хоть объяснили бы почему)))

По сабжу, я вообще, например, не использую while - тут кто к чему привык, кому как удобно. с for - код читабельнее это 100%, скорости почти одинаковы. Так что, профессиональнее там - где читать удобно и понятно

Wolsh
11.03.2013, 16:14
in4core, Вы сами-то заметили, что у Вас условия разные?
Первое выдаст трейс, если count=-1, а второе — нет.
Это ответ на вопрос "почему второй", если такой возникнет. Потому что так вероятность ошибки "не учёл" практически исключена.

in4core
11.03.2013, 16:20
in4core, Вы сами-то заметили, что у Вас условия разные?
Первое выдаст трейс, если i=-1, а второе — нет.
Угу условия разные для AS3 - потому, что -1 по сути должно быть false. Но по скольку здесь это будет true - да , условия получаются разные.

Поэтому можно заменить на private var str:String = ""; и проверки if(str) против if(str == "")

___________
Или вот например - можно назвать знатным трололо использовать int в циклах вместо uint. ( ну когда нужно ). А ведь 99% разработчиков используют именно int

alatar
11.03.2013, 16:24
Отсюда следует резонный вопрос, как вывести критерии профессионализма из задачи в которой сравниваются красное с теплым, но при этом не уточняется, что получить надо только красное или только теплое?

expl
11.03.2013, 16:25
Зачем применительно к скриптовому языку обсуждают способы выиграть несколько команд процессора?
Потому что на этом скриптовом языке пишут игры, не часть сценария игры, не настройки сущностей, как на lua - а самую основную логику игры. И вопрос производительности стоит очень остро. На нём физические движки пишут и надо сказать - не быстро они работают - нельзя там игнорировать низкоуровневые оптимизации.

Не, тут конечно один товарищ пытался оптимизировать итерацию по 10-ти элементам за кадр. И совершенно не беспокоился о времени, потраченном на обработку каждого элемента и о тоннах другого кода, который выполняелся в том же кадре.
Но это общие вопросы оптимизации - в С++ тоже _не_ надо оптимизировать участок, который отжирает .1% от общего времени работы игры. Надо критические места оптимизировать. Но в as3 коде такие места встречаются и часто именно код является источником тормозов, хотя рендеринг дотридешного флеша тоже медленный как сволочь.

caseyryan
11.03.2013, 16:30
А вот какой из этих 2х примеров профессиональнее??! )))
Профессиональнее всегда тот, где код легче читается человеком.
Кстати такое не явное приедение к типу boolean далеко не во всех языках прокатит. Например джава не приведет автоматически null к false, а кинет NullPointerException. Тогда как в ас3 это в порядке вещей.
Да и для ас3 где-то читал рекомендации, что лучше писать так:

if (someObject != null) {
// здесь код
}

вместо этого:

if (someObject) {
// здесь код
}

Wolsh
11.03.2013, 16:34
Отсюда следует резонный вопрос, как вывести критерии профессионализма из задачи в которой сравниваются красное с теплым, но при этом не уточняется, что получить надо только красное или только теплое?Предположение о задаче как раз и строится на том факте, что в "развернутой" версии задача ясна и не подразумевает разночтений. Другими словами, если бы автор хотел условие if(count != 0), он так бы и написал)).

expl
11.03.2013, 16:35
В соглашении от Adobe рекомендуют if (someObject) {
Но мы с товарищем при составлении нашего кодостайла решили, что Adobe не прав :)

alatar
11.03.2013, 16:35
Да и для ас3 где-то читал рекомендации, что лучше писать так:
Лучше или хуже, можно понять только в конкретной ситуации. Если someObject не типизирован, то там может быть и не null.

in4core
11.03.2013, 16:42
Ну раз пошла такая пьянка. Давай те рассуждать из разряда нормальных языков, той же JAVA. Что должен принимать на входе if ? - верно тип Boolean . someObject - Это типа Boolean ? - нет, Number это тип Booelan? То же нет... В связи с этим, можно выразить всеобщий код-стайл так :
1. Если переменная объявлена как тип Boolean - нужно писать if(isMyHouse)
2. Если переменная не является boolean - значит нужно САМОМУ приводить ее к виду, а не давать компилятору делать это. Почему так? - А чтобы было понятно, хотя бы самому , + в этом случае - мы используем общий код стайл для всех языков, и нас никогда не постигнет NullPointerException

alatar
11.03.2013, 16:50
Другими словами, если бы автор хотел условие if(count != 0), он так бы и написал)).
Автор хотел условие if (professional) :) А теперь хочет всегда знать тип переменной, как в "нормальных" (интересно узнать критерии нормальности, что бы это не значило) языках.

caseyryan
11.03.2013, 17:14
Если someObject не типизирован, то там может быть и не null.
Ну, нетипизированный объект в ас3 тоже как-то не по фен шую

alatar
11.03.2013, 17:21
Скажите спасибо, что не по фен-шую. ActionScript все таки лучше стандартизирован. :D

etc
11.03.2013, 17:39
Что вообще за пустотелый бред - мерить профессионализм циклами? это знатное трололо !!!

А вот какой из этих 2х примеров профессиональнее??! )))

private var count:int = 0;
.................................
if(count) trace("hello");

или
................................
if(count > 0) trace ("hello");

???
Профессиональнее «if (».

Tails
11.03.2013, 17:45
Самое профессиональное условие, это: a>b?c:d, особенно если запихать в одну строку сразу 5 условий, и цикл в придачу.

GBee
11.03.2013, 18:06
Самое профессиональное условие, это: a>b?c:d, особенно если запихать в одну строку сразу 5 условий, и цикл в придачу.

Это крик "смотрите, как я могу!" ну и плюс 5-10 минут к разбору выражения другим прогером ну или самому. :о)

i.o.
11.03.2013, 18:31
А можно пример? Немогу даже представить такой ситуации.

var len:uint = arr.length;
for (var i:int = 0; i < len; i++){
}

Может кто нибуть высказаться в пользу цикла while?
Конечно. В while нет непонятных точек с запятой :)

var i:int = -1;
var len:uint = arr.length;
while (++i < len) {
}

elder_Nosferatu
11.03.2013, 19:54
Товарищ in4core назвал меня тролем и, гляжу, не безосновательно... Хороший и затяжной срач получился, даже незаметно с циклов на условия перекинулись.

Кому интересно развивать тему - желаю удачи.
Кому это не нравится - приношу свои извинения.
Ответ на свой вопрос я получил, всем спасибо :)

GBee
11.03.2013, 19:56
Какой ответ то?

wvxvw
11.03.2013, 20:24
Угу, хорошо, ...для С#, Ocaml, F#. Но никак не для ActionScript3, потому что:
- нет типизации функций,
- вызов функции непростительно дорог.
В сортировке только используется и то только потому, что копипастить алгоритм сортировки слишком дико. Но в особо критических местах именно не быстрый вызов функции заставляет делать свою реализацию сортировки.
В as3 я использовал функции высших порядков только для выбора наиболее подходящих значений/вариантов/объектов по критериям. Критерии были как раз функциями, передававшимися в алгоритм выборки. Но это использовалось только в AI, туториале. В основной логике такого не было - дорого потому что и не типизировано.

Да даже и в C# как-то стремно эти штуки использовать, мало ли как на производительности скажется, только когда без них код слишком страшным становится.
В AS3 пишется куча скучного ГУЙ-кода, в котором совершенно не нужно врукопашную что-то оптимизировать. Даже любая игра большей частью состоит из ГУЙ-кода, и только небольшая часть посвящается сложным вычислениям.
Ну и вот сейчас же пишут оптимизирующий компилятор.
Ну и вообще, нужно же и по-сторонам смотреть. Даже если сейчас технически нет возможности сделать так, как нужно / хочется в AS3, это не значит, что такой возможности никогда не будет. Может кто-то соберется и сделает, а может Адоби разродится, а может человек переквалифицируется.
Кстати, по поводу функций высших порядков - я думаю, Страуструп еще об этом говорил.

elder_Nosferatu
11.03.2013, 21:07
Какой ответ то?

- приверженность циклу while - сила привычки;
- в одинаковых условиях циклы while и for не могут похвастаться производительностью друг перед другом;
- других явных факторов, на которые стоит обратить внимание, никто не упомянул;
- *****код можна написать множеством способов, не важно какие конструкции использовать.

Добавлено через 4 минуты
Даже и не подозревал, что на форуме есть "запикивалка" :)

Wolsh
11.03.2013, 21:43
- других явных факторов, на которые стоит обратить внимание, никто не упомянул;Фраза сформулирована неверно. Должно быть: "читабельность кода для меня не является фактором, на который стоит обратить внимание".

elder_Nosferatu
11.03.2013, 23:01
Фраза сформулирована неверно. Должно быть: "читабельность кода для меня не является фактором, на который стоит обратить внимание".

Читабельнось как бы всегда подразумевается, но не стоит на первом месте. А в данном случае меня больше интересовала техническая сторона. К примеру, если бы цикл for существовал только формально для удобочитаемости, а при выполнении "конвертировался" в тождественный ему цикл while, тогда стоило бы задуматься... Ведь если бы исходный код исполнялся интерпретатором, то такие операции делались бы "на лету" и в критических местах можно было бы пожертвовать читабельностью в пользу производительности. А даже если и отмести какую нибуть практическую выгоду, то все равно интересно чем эти две конструкции отличаются.

ЗЫ: Мне, наверное, сложно дается русский язык и я немогу на нем толково изъясняться, ведь никто так и не понял, что я не меряю профессионализм программиста циклами. Я просто заметил, что многие (но далеко не все), чей код логичен и понятен, у кого можна научится каким нибуть идеям, не используют цикл for.

expl
11.03.2013, 23:02
В AS3 пишется куча скучного ГУЙ-кода, в котором совершенно не нужно врукопашную что-то оптимизировать. Даже любая игра большей частью состоит из ГУЙ-кода, и только небольшая часть посвящается сложным вычислениям.
Ну и вот сейчас же пишут оптимизирующий компилятор.
Ну и вообще, нужно же и по-сторонам смотреть. Даже если сейчас технически нет возможности сделать так, как нужно / хочется в AS3, это не значит, что такой возможности никогда не будет. Может кто-то соберется и сделает, а может Адоби разродится, а может человек переквалифицируется.
Кстати, по поводу функций высших порядков - я думаю, Страуструп еще об этом говорил.
Напишут - не напишут. Мы живём в настоящем.

Да, я бы предпочёл лепить везде свертки, фильтры, отображения и выборки вместо циклов, хотя ещё не очень понимаю в как в функциональном стиле по-человечески обработать что-то 2-мерное, а не только деревья и списки (только транспонирование списка списков чего стоит)

Но так не получится.
GUI - морды на AS3 я практически не делал, делал игры, а там много критических мест - и везде лепить подобие C#-ного LINQ не получится. Т.е. придётся думать где можно, где нельзя. А ещё отвыкать от старого доброго "циклоидного" подхода. В итоге получится и отвыкание и код быстро работать не будет. И ещё думать надо будет, критическое место или нет.

Поэтому не вижу смысла использовать функции высшего порядка если сильно не припрёт.
wvxvw, сами то часто функции гоняли в as3-проектах? У меня чаще всего они вместо объектов фабрик использовались, а не для обработки данных.

А, ну там ещё из-за отсутствия типизации стремно узлы из функций городить.

На других, приспособленных для этого платформах - пожалуйста, на полную катушку. Но не на as3. По-крайней мере не сейчас.

wvxvw
11.03.2013, 23:58
Речь как бы не про Linq... и не про функциональное программирование. Речь о том, что итерация - это маленький блок программы, но программа - существо большее чем совокупность таких микро-блоков, в ней есть конструкции состоящие из этих самих микроболоков, и хороший программист оперирует коснтрукциями разной сложности (сложности = уровня абстракции).
Точно так же, как цикл - совокупность команд байткода, но программа - это что-то большее чем все команды байткода которые ее составляют.
Опять же, хороший программист должен уметь создавать абстракции более высокого уровня, чем примитивы заготовленные в языке. А выбор примитива данного в языке ничего не говорит об уровне...
Более того, программист, который не умеет создавать такие абстракции - это плохой программист. Это человек, который будет писать полотна из циклов и условий, не в состоянии выделить концептуальные части программы в функции, классы, пакеты, или будет создавать классы / модули с плохо распределенными полномочиями (т.как не умеет правильно проанализировать составляющие и построить абстракцию, которая бы соответствовала назначению программы). Какими бы примитивами он ни пользовался.

alexcon314
12.03.2013, 11:27
А вот еще одно неазмысловатое объяснение. Однако, выводы тут прямо противоположные тем, что изложил в первом посте ТС - FOR чаще встречается, чем WHILE.

iflamberg
12.03.2013, 14:31
Ну вы, господа, развели демагогии на 8 страниц. Место теме в флейме =)

nuToH
12.03.2013, 14:45
//сарказм.
вот цикл для профи:
один вызов геттера length, супербыстрая математика!
for (var i:int = arr.length; (i=~-i)^-1; ) {
trace(arr[i]);
}

iflamberg
12.03.2013, 15:00
(i=~-i)^-1
Кайф. Минут 5 догонял.

caseyryan
12.03.2013, 15:21
Кайф. Минут 5 догонял.
Я видимо туп ) Не догнал

FlashRus
12.03.2013, 15:31
//сарказм.
вот цикл для профи:
один вызов геттера length, супербыстрая математика!
for (var i:int = arr.length; (i=~-i)^-1; ) {
trace(arr[i]);
}

Чёта он ни разу не супербыстрый....



t = getTimer();
for (i = 1000000; (i=~-i)^-1; ) {
}
tf.appendText(getTimer() - t + "\n"); // 8 мс

t = getTimer();
for (i = 0; i < 1000000; i++) {
}
tf.appendText(getTimer() - t + "\n"); // 3 мс



Классический вариант более чем в два раза быстрее.


P.S.
Хотя стоп, туплю... Если у нас getter, а не константа то картина несколько другая:



t = getTimer();
for (i = arr.length; (i=~-i)^-1; ) {
}
tf.appendText(getTimer() - t + "\n"); // 7

t = getTimer();
for (i = 0; i < arr.length; i++) {
}
tf.appendText(getTimer() - t + "\n"); // 7



Как можно заметить - результаты равны.

НО, если сделать так (ниже), то получается вообще самый-самый быстрый вариант:



t = getTimer();
for (i = arr.length; i >= 0; i--) {
}
tf.appendText(getTimer() - t + "\n"); // 2 мс

GBee
12.03.2013, 15:33
Побитовые извращения

nuToH
12.03.2013, 16:13
FlashRus, это была шутка. но если бы я делал ставки, то поставил бы на
var i:int = arr.length;
do {
--i;
} while ( i > 0 );
но только из спортивного интереса, реальная разница в производительности смысла не имеет.)
в реальной работе для перебора использую
for each( var i:Тип in arr ) {
}

FlashRus
12.03.2013, 16:36
Ну да)
Лучше уже тело цила оптимизировать)

GBee
12.03.2013, 18:14
но если бы я делал ставки, то поставил бы на
и схватили бы исключение при обращении к массиву с 0 длиной.

caseyryan
12.03.2013, 20:13
А кто-то реально использует циклы do while?
У меня вот ни разу не было ситуации, где возникала бы необходимость в таком извращении

iflamberg
12.03.2013, 20:28
Всегда спешишь назвать что-либо "извращением".
do...while удобен в случаях, когда тебе нужно, чтобы цикл выполнился хотя бы один раз независимо от условий.

caseyryan
12.03.2013, 22:31
не удобен. Удобнее задать начальное значение переменной на 1 больше

iflamberg
12.03.2013, 22:42
Вот тут как увеличить значение переменной на 1 больше?

do { // process blocks until last block or error
var last:int = bits(1); // one if last block
var type:int = bits(2); // block type 0..3

if(type == 0) stored(buf); // uncompressed block
else if(type == 3) throw new Error('invalid block type (type == 3)', -1);
else { // compressed block
lencode = {count:[], symbol:[]};
distcode = {count:[], symbol:[]};
if(type == 1) constructFixedTables();
else if(type == 2) err = constructDynamicTables();
if(err != 0) return err;
err = codes(buf); // decode data until end-of-block code
}
if(err != 0) break; // return with error
} while(!last);

Здесь last работает просто как флаг. Можно было бы:

while (1){
...
if (!last) break;
}

Но do...while же удобней.
Это кусок кода из zip-упаковщика.

Psycho Tiger
12.03.2013, 23:00
А кто-то реально использует циклы do while?
Использую. Редко, мне не нравится, но порой это почти единственный адекватный способ решить задачу.

in4core
13.03.2013, 04:05
но порой это почти единственный адекватный способ решить задачу. Ну ка а можно пример *адеквата* ? Я вот не использую while вообще - и считаю данный вариант цикла убогим по реализации, и не читабильным как таковым. Жаждим примера...ну очень жаждим

ChuwY
13.03.2013, 09:10
В пылу дискуссии как будто бы затерялся тот факт, что в условиях бывает не только счетчик с шагом.
Сам я обычно и выбираю конструкцию исходя из того, сводится ли условие к обнаружению значения счетчика в заданном диапазоне.
В общем, исхожу из определения, данном, кажется, во встроенной в turbo pascal справке:
for -- цикл с заданным числом повторений.

do while во флеш-практике таки приходилось использовать, но пример не вспомню.
А вот в вышеупомянутом паскале с его помощью логичнее всего обрабатывалось нажатие определенных клавиш. По крайней мере, тогда мне так казалось :) Сейчас утверждение кажется несколько сомнительным.

Добавлено через 7 минут
Насчет абстракций более высокого уровня и их (уровней) разделения.
В тех местах, где производительность не критична, или работа находится на начальном этапе, все же стремлюсь к использованию for-in\for-each-in, когда задача сводится к перебору, так как "для каждого из ${список элементов предметной области\ уровня}" звучит куда более близко по смыслу к цели. А заодно от лишней на этом уровне сущности счетчика избавляемся.

Добавлено через 18 минут
Но вот использовать высокоуровневые примочки Array\Vector с коллбеками (кроме сортировки, ессна) побаиваюсь традиционно. И даже местами переписываю в более примитивные конструкции.
Отчасти из-за отсутствия типизации функций, отчасти из-за... отсутствия привычки, быть может.

Второй аргумент не особенно убедителен, так что очень интересно...
что же скажут профи про опыт использования методов (forEach\every\some\map\filter)!

expl
13.03.2013, 12:13
что же скажут профи про опыт использования методов (forEach\every\some\map\filter)!
forEach самый бесполезный. Его можно использовать только для применения какого-то действия к объекту.
Но нужен метод doSomething(item). Обычно проще цикл написать.
Для накапливания како-го то значения - бессмысленно - придется либо делать анонимки, либо выносить состояние в поле класса, когда оно могло бы быть переменной.

Остальные - не использую, т.к. не сильно упрощают код - там же функции делать надо, не анонимки же использовать.

Я в as3 использовал другую и, в общем-то, одну самопальную функцию:

public function find(foreachable:Object, filter:Function/*(Object):bool*/, criterions:Array/*of (Object):int*/, defaultValue:Object):*

Например для AI надо выбрать противника, который имеет меньше всего здоровья, но если найдется несколько человек с одинаково низким здоровьем - надо выбрать какого по ближе (поэтому criterion возвращает int, чтобы == имело смысл):

_invertDistance_unit = selfUnit;
var enemy:Enemy = find(enemies, isCanAttack, [getInvertHealth, getInvertDistance]);
_invertDistance_unit = null;
...
private function getInvertHealth(enemy:Enemy):int
{
return -enemy.Health;
}
private function getInvertDistance(enemy:Enemy):int
{
return -_invertDistance_unit.GetDistanceTo(enemy);
}

Если без функций - получится неслабый союз цикла и ифов, в котором легко накосячить. И читалось бы тяжело.
Это действительно, несмотря на создание кучи мелких функций драматически уменьшало объёмы кода и увеличивало читабельность. Но применялось только в специфических частях игры.