Предложение отправить issue по поводу цикла for
|
|
electrik | Дата: Суббота, 20.05.2023, 03:42 | Сообщение # 1 |
Полковник
Группа: Друзья
Сообщений: 182
Статус: Offline
| Всем часто приходится работать с циклом for. Некоторые занимаются адаптацией программ с других языков. как вот вам такая конструкция, ещё не надоела?
Под size, подразумевается не константа, а переменная. конечно можно сделать так:
Код while i < size i +=1 wend
А если это цикл, в котором сложное ветвление с continue! Как мы знаем, что только в цикле for continue делает инкремент переменной. Идея понятна? в сложных ветвлениях просто можно забыть сделать инкремент. Поэтому, в некоторых случаях for всё же лучше. А теперь представим вложенные циклы в которых идёт бессмысленный декремент на единицу. Да и опять таки, при переписывании кода, по запарке можно забыть этот декремент вписать. Непонятно, почему в бейсиках этот вопрос до сих пор не решён. Вопрос, какой синтаксис им предложить? а вот тут даже не знаю. Ну скажем:
Может странно выглядит. Можно иначе, но это уже не будет увязываться с константами:
Ну а если я захочу написать:
Стрёмненько выглядит. Первый вариант с константами будет красивей:
for i = 1 to < 10 /code] Стоит ли что-то менять, или пусть бейсик будет как есть? Мне кажется, что некоторые фишки добавлять нужно, ибо бейсик уже не для обучения в школе. В школьных задачах действительно проще писать в лоб от 1 до 10, но бейсик уже не школьник. Короче, какие ещё придумаете конструкции, которые не будут выбиваться из синтаксиса бейсика?
|
|
| |
haav | Дата: Суббота, 20.05.2023, 14:49 | Сообщение # 2 |
Генералиссимус
Группа: Администраторы
Сообщений: 1373
Статус: Offline
| Это же почти аналог сишной конструкции FOR. Вряд ли кому-то это придется по вкусу. Хотя , кто знает.
Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
|
|
| |
zamabuvaraeu | Дата: Вторник, 23.05.2023, 07:00 | Сообщение # 3 |
Подполковник
Группа: Друзья
Сообщений: 149
Статус: Offline
| Я против. Язык уже итак раздут дублирующими и неоднозначными конструкциями, и должен быть только один способ получения результата.
|
|
| |
ntvgjhfnj | Дата: Вторник, 23.05.2023, 18:37 | Сообщение # 4 |
Лейтенант
Группа: Проверенные
Сообщений: 61
Статус: Offline
| Цитата "zamabuvaraeu" () Язык уже итак раздут дублирующими и неоднозначными конструкциями, и должен быть только один способ получения результата. Способы нужны разные или один ,но универсальный.
polopok
|
|
| |
sashasold | Дата: Среда, 24.05.2023, 19:14 | Сообщение # 5 |
Лейтенант
Группа: Пользователи
Сообщений: 41
Статус: Offline
| "for i = 1 to size-1" Чтобы не сбится, и для некой оптимизации я пишу predel = size-1 for i = 1 to predel 'Тело Next
А если много ветвлений, вложенных циклов, то может лучше i=0 Do until i=predel i+=1 'Тело Loop
Do loop вообще универсальней, а с подменой на predel код быстрее, при большом количестве повторений
Добавлено (25.05.2023, 00:02) --------------------------------------------- Да и еще если применять сложные условия и разрыв цикла For i=1 to abv If a=b then exit for Next Отслеживаем значение i
Интересно, что если цикл прерывается при exit for то значение i ожидаемо А вот если цикл завершается полностью, то i не будет равно abv как ожидается, а будет abv+1. Так что видимо цикл for next, реализоан внутри, через ограничение i>abv
Так, вспомнился нюанс)
Сообщение отредактировал sashasold - Четверг, 25.05.2023, 00:03 |
|
| |
electrik | Дата: Вторник, 13.06.2023, 23:31 | Сообщение # 6 |
Полковник
Группа: Друзья
Сообщений: 182
Статус: Offline
| Да петлёй то можно, но как я говорил, случаи бывают всякие, и при очередном continue можно не добавить счётчик. Синтаксис менять и не надо, просто нужно добавить новые конструкции. Можно и универсальный while сделать, к примеру, шлёпнуть макросы endwhile и continuewhile, которые будут всё прибавлять где надо, но это костыли в рамках своих проектов. А если мне нужно прибавлять не единицу а другое число, вообще неизвестное из переменной, короче это хрень. Я переписываю одну программу с C, так там for и с кучей continue. Как я долго матерился когда искал ошибку, а всё вина в том, что там замороченый for, который можно переписать только используя while, и я конечно же после continue забыл заинкрементить переменную:
Код for (i = 0; (i < (sizeof(clause_terminations) / sizeof(uint16_t))) && (clause_terminations [i]!= termination); i++)[/i]
Короче for с несколькими условиями. Такое на бейсике можно сделать только при помощи while.Добавлено (31.08.2023, 19:19) --------------------------------------------- Вот что я попытался намудрить на макросах, в C стиле, но оно не будет или не правильно будет работать в случае вложенных циклов. Изначальный код был с оф форума, но они сразу написали что это только для невложенных циклов. пример первый:
Код #macro CFOR(startexpr,condexpr,stepexpr) startexpr while condexpr #ifdef CNEXT #undef CNEXT #endif #ifndef CNEXT #macro CNEXT?() stepexpr wend #endmacro #endif #endmacro
dim i as integer CFOR(i=0,i<5,i+=1) print "i=",i cfor(dim j as integer =0,j<10,j+=1) print "j=", j CNEXT CNEXT /code] Пример второй:
#macro CFOR(startexpr,condexpr,stepexpr) startexpr while condexpr #ifndef CNEXT #macro CNEXT?() stepexpr wend #endmacro #endif #endmacro
dim i as integer CFOR(i=0,i<5,i+=1) print "i=",i cfor(dim j as integer =0,j<10,j+=1) print "j=", j CNEXT CNEXT
Первый код будет не рабочий, и вот что получается в развёрнутом виде при помощи ключа -pp:
dim i as integer i=0 while i<5 print "i=",i dim j as integer =0 while j<10 print "j=", j j+=1 wend CNEXT
Последний макрос не развернулся, но оно и понятно, он отменен при помощи #undef. Развёрнутый второй код рабочий но неправильно:
dim i as integer i=0 while i<5 print "i=",i dim j as integer =0 while j<10 print "j=", j i+=1 wend i+=1 wend
В данном примере, при повторном вызове cfor, макрос cnext, продолжает отдавать параметры как бы от первого вызова cfor. В первом примере, мы его андефайним, тогда конец второго цикла указывает на правильную переменную, а поскольку макроса больше нет, мы не можем закрыть первый цикл. Пока тут нет CCONTINUE, но это пару строчек шлёпнуть. Пока ничего умного в голову не пришло, чтобы всё это работало во вложенных циклах, и не по извращенски. В макросахх нужно делать или свои #scope блоки, или стек макросов или параметров. Они уже потихоньку высовывают наружу потроха компилятора, но не быстро. Офигенную вещь придумали, такую как уникальные имена, я даже попытался это как-то прикрутить к данным макросам, но оно не так работает, как я предполагал. Стек параметров, или макросов было бы круто. Да, оно будет при компиляции жрать ресурсы и скорость, но это сразу бы сильно развязало руки. Выглядело бы это так: __FB_PARAM_PUSH(macroname,param) Ну или как-то так. Таким образом, вообще ненужны были бы вложенные макросы, а просто их параметры хранились бы в стеке, а лучше в хэше, и ты мог бы использовать параметры любого, подчёркиваю, вызванного макроса, доставая их из стека или хэша. Да, и без scope будет не обойтись, потому что одноимённых вложенных названий может быть много, а это duplicate definition. Если нужно достать произвольные параметры, лучше использовать хеши, тогда вообще не нужно будет думать сколько взял и сколько положил. Но будет условие, брать и класть ты можешь в любом порядке, но если сколько положил, значит после использования столько освободи. Незнаю, что будет с компилятором, если кто-то нашлёпает макросов, как шаблонов в boost, и как он будет долго компилировать, но это, как говориться, можно пояснить, что злоупотреблять не нужно. Вообще давно пора инлайн функции, вот где сила. давно считается, что макросы - это рассадник трудноотлавливаемых ошибок. Согласен, костыльно, но правильно написанное работает быстро.
Сообщение отредактировал electrik - Вторник, 13.06.2023, 23:34 |
|
| |
zamabuvaraeu | Дата: Воскресенье, 03.09.2023, 22:55 | Сообщение # 7 |
Подполковник
Группа: Друзья
Сообщений: 149
Статус: Offline
| Цитата Короче for с несколькими условиями. Такое на бейсике можно сделать только при помощи while. Нет. Можно через For. Оператор For — это не просто какая‐то команда, выражение или ключевое слово, это настоящий оператор, который можно переопределить. Для начала определим структуру, которая будет выражать наш переопределённый For: Код Type CycleCounter Declare Constructor( ByVal n As Integer ) ' Переопределение для неявного использования Declare Operator For ( ) Declare Operator Step( ) Declare Operator Next( ByRef end_cond As CycleCounter ) As Integer ' Счётчик i As Integer End Type
Я не знаю что такое clause_terminations, но полагаю что это какая‐то строка. Используем переопределённый For. В качестве счётчика цикла будет использоваться наша структура CycleCounter: Код Dim Shared clause_terminations As ZString * 265 = "Hello world!" Dim Shared termination As Integer = 0
For i As CycleCounter = 0 To 100 If clause_terminations[i.i] = 32 Then ' Теперь можно делать Continue ' и счётчик не забудет обновлять сам себя Continue For ' это просто для примера ' чтобы не печатать символы с пробелом End If ' печатаем текущее значение счётчика и символ из строки ' для самоуспокоения Print i.i, clause_terminations[i.i] Next
Ну а теперь реализация оператора For Код Constructor CycleCounter( ByVal n As Integer ) ' Конструктор, просто инициализируемся i = n End Constructor
Operator CycleCounter.For( ) Print "implicit step" End Operator
Operator CycleCounter.Step( ) ' Эта функция будет вызываться для приращения счётчика ' по умолчанию приращиваем счётчик на единицу this.i += 1 End Operator
Operator CycleCounter.Next( ByRef end_cond As CycleCounter ) As Integer ' Эта функция вызывается для проверки окончания цикла ' Параметр end_cond — это то, что стоит в выражении To ' то есть мы должны сравнить себя с параметром end_cond ' но в этом примере мы игнорируем этот параметр ' Мы должны вернуть 1 если цикл ещё не завершён ' и 0 когда цикл завершён ' Тут немного изменённое условие ' Но можно взять любое другое условие If i < (SizeOf(clause_terminations) \ SizeOf(WString)) AndAlso clause_terminations [i]<> termination Then Return 1 End If Return 0 End Operator[/i]
Этот простой пример демонстрирует как добавить сколько угодно условий в оператор For. И без всякой возни с макросами. И будет работать с Continue и вложенными циклами.
На офсайте лежат примеры с переопределением For, рекомендую ознакомиться https://www.freebasic.net/wiki/KeyPgOpStepДобавлено (04.09.2023, 23:17) --------------------------------------------- Цитата Вообще давно пора инлайн функции, вот где сила. Это уже давно существует. Компилятору нужно только подсказку сделать: 1. Определяем функцию как Private. 2. Компилируем через gcc "-gen gcc" с оптимизацией (-O 2 или -O 3).
Все приватные функции оптимизатор отлично встраивает.
|
|
| |
electrik | Дата: Воскресенье, 17.09.2023, 03:54 | Сообщение # 8 |
Полковник
Группа: Друзья
Сообщений: 182
Статус: Offline
| Это всё не плохо конечно, и про перегрузку операторов я знаю, но это получается подгонка оператора под конкретный случай. Я одной строкой не могу написать элегантно. а я говорю про универсальность для базовых типов. В наше время на это можно забить, но в случае для счётчика базового типа выделять целый класс - ну такое. Ведь внутри все for step next в классе выглядят как отдельные функции. Тоесть, для того чтобы заинкрементировать integer, компилятору нужно вызывать целую функцию. Для настоящего ООП, перегрузка операторов оправдано, но не для базовых типов. Конечно можно попробовать проделать ваш трюк с приватными функциями и с оптимизацией для GCC, тогда может код развернётся как инлайн. И то я не уверен, что это сработает в классе - нужно проверить. Нехватает в бейсике гибкого for, ну как не крути. в C ты можешь даже одним фор инкрементировать несколько переменных, и проверять несколько условий и всё это одной строкой и без перегрузки и без создания своего типа для базового типа. И я как раз начал этот разговор именно и-за оптимизации, чтобы for был не просто топорный: for i = 1 to 10 А for i = 1 to < 10 или for i = 1 to <=10 или for i = 0 to i < 10 Всё можно заменить и while и do ... loop, но просто есть более лёгкий путь, и самое главное что там есть что и куда оптимизировать. Таким образом будет меньше ошибок и код оптимизирован и выглядеть элегантно. В шестедисятые года это придумывалось для базового обучения программированию, но в двадцать первом веке, бейсик вырос, и конструкции тоже должны меняться. Это перегрузка языка, согласен, но если вы хотите оставить обратную совместимость, этого не избежать. С удовольствием бы подключился к проекту и сделал то что нужно, но мозгов не хватает разобраться с компилятором. Много было попыток, но безуспешно. Плохо я знаю теорию построения компиляторов.
|
|
| |
zamabuvaraeu | Дата: Среда, 18.10.2023, 19:37 | Сообщение # 9 |
Подполковник
Группа: Друзья
Сообщений: 149
Статус: Offline
| Цитата Конечно можно попробовать проделать ваш трюк с приватными функциями и с оптимизацией для GCC, тогда может код развернётся как инлайн. Да.
Например, нам нужна простая программа, которая перечисляет каталоги. Main.bas: Код #include once "FileIterator.bi" #include once "crt.bi"
Const FormatString = !"%s\r\n"
Function EntryPoint Alias "EntryPoint"() As Integer For fff As FileIteratorW = WStr("*") To WStr("") wprintf(@WStr(FormatString), @fff.FindData.cFileName) Next Return 0 End Function
Заголовочный файл FileIterator.bi: Код #ifndef FILEITERATOR_BI #define FILEITERATOR_BI
#include once "windows.bi"
Type FileIteratorW Declare Constructor(ByRef ListingDir As WString) Declare Destructor() Declare Operator For() Declare Operator Step() Declare Operator Next(ByRef endCond As FileIteratorW) As Integer FindData As WIN32_FIND_DATAW hFind As HANDLE pListingDir As WString Ptr resFindNext As BOOL End Type
#endif
И собственно файл итератора FileIterator.bas: Код #include once "FileIterator.bi"
Constructor FileIteratorW(ByRef ListingDir As WString) hFind = INVALID_HANDLE_VALUE pListingDir = @ListingDir resFindNext = TRUE End Constructor
Destructor FileIteratorW() If hFind <> INVALID_HANDLE_VALUE Then FindClose(hFind) End If End Destructor
Operator FileIteratorW.For() hFind = FindFirstFileW( _ pListingDir, _ @FindData _ ) End Operator
Operator FileIteratorW.Step() resFindNext = FindNextFileW( _ hFind, _ @FindData _ ) End Operator
Operator FileIteratorW.Next(ByRef endCond As FileIteratorW) As Integer If hFind = INVALID_HANDLE_VALUE Then Return 0 End If If resFindNext = 0 Then Return 0 End If Return 1 End Operator
Берём шланг и компилируем программу, получаем на выходе исполняемый файл размером 2048 байт (!). В результирующем коде нет никаких вызовов функций и операторов.
Рядом лежит аналогичный пример без оптимизаций: его размер 23 килобайта.
|
|
| |
|