MS Small Basic в настоящее время является лучшим учебным текстовым языком программирования. С появлением современной среды программирования SB-Prime, библиотеки LitDev и ряда других библиотек он получил великолепные возможности, позволяющие писать на нём сложные, полезные и интересные программы, которые можно использовать не только в учебных проектах, но и для решения вполне серьёзных задач, однако, ему присущ ряд недостатков, делающих его непригодным для создания действительно серьёзных проектов…
Переменные в MS Small Basic не требуют объявления. Здорово? На первый взгляд — очень! Ничего не нужно заранее продумывать, только следи, чтобы переменная получила значение до её использования — и всё. При этом переменные как бы сами «решают», какого они типа — в зависимости от того, что в них записано. Это кажется очень удобным, особенно — для учебного языка программирования. Но если копнуть чуть глубже, мы увидим, что далеко не всё так здорово, как кажется на первый взгляд.
Как можно реализовать такие простые и умные переменные? Реализовать их можно либо созданием сложного класса, который сам определяет тип передаваемых данных, хранит их в одной из подходящих внутренних переменных, выполняет проверки на корректность и преобразования данных в случае необходимости, либо…
Разработчики MS Small Basic решили проблему создания неких «универсальных» переменных, подходящих для хранения любых типов данных очень специфическим (зато простым и быстрым!) способом. Начать с того, что переменные в MS Small Basic все(!) — действительно одного единственного типа: и числовые, и символьные, и текстовые, и даже массивы(!). Фантастика? Нет. Решение, найденное разработчиками, конечно в принципе имеет право на существование, но крайне примитивно и принесло с собой кучу неудобств при работе с данными. Я бы даже сказал, разработчики поленились сильно напрягаться — они просто придумали хранить любые переменные как… (барабанная дробь!) …текстовые строки! Настоящие программисты, я думаю, в шоке, как от простоты идеи, так и от потенциального количества проблем, которые она за собой тащит. Ну и от ленивости разработчиков, я полагаю, тоже…
Итак, что же мы имеем? Мы имеем довольно неуклюжий способ уйти от проблем при создании класса умных переменных. Зато у нас есть «умные» строки, которые при каждой операции переписываются в новую область памяти… («Да чёрт с ней, с оптимизацией!»)
И эти же «умные» строки могут хранить в себе числа. Ну, в целом, да, действительно могут — в текстовом представлении, что, впрочем, можно сделать в ЛЮБОМ языке программирования — ну какая разница, что хранить в строковых переменных, особенно в «умных»? Текст — он и в Африке текст, а распознать его можно — как угодно…
Как производится «разбор» этих «умных строк»:
1) Это массив? Если да — то значит у нас есть массив «умных» строк, требующих разбора.
2) Это число? Да. Ну, тут, вроде, всё просто.
3) Если не 1) и не 2) , то это — просто текстовая строка.
В зависимости от того, можно ли преобразовать переменную в число или нет, она будет рассматриваться как число или текстовая строка. Таким образом, все следующие примеры — это сложение чисел (Где там логика-то?!):
TextWindow.WriteLine("3"+"4")
TextWindow.WriteLine(3+4)
TextWindow.WriteLine(3+"4")
А вот это — уже строки, поскольку «3a»
или «:»
не могут быть преобразованы в числа.
TextWindow.WriteLine("3a"+"4")
TextWindow.WriteLine(3+":"+4)
Зато мы легко можем увидеть, как выглядит «умная» строка с массивом, выполнив следующие команды:
a[1] = "hello"
TextWindow.WriteLine(a)
Кроме того, все остальные, в том числе и графические объекты хранятся в Small Basic в виде «умных» строк, поэтому выполнив эти команды, вы увидите в консоли идентификатор эллипса:
ellipse = Shapes.AddEllipse(20,20)
TextWindow.WriteLine(ellipse)
Поэтому стандартную операцию перемещения нашего эллипса:
Shapes.Move(ellipse,50,50)
Мы можем заменить на:
Shapes.Move("Ellipse1",50,50)
или на
Shapes.Move("Ellipse"+1,50,50)
Ничего не изменится! Теперь вы видите, какой простор для появления недиагностируемых ошибок оставляют такие вот «простые и классные» переменные без типа. Когда вы перейдете к серьёзным задачам, вы столкнетесь с необходимостью правильного выбора типов или создания собственных типов, но SmallBasic сделает всё за вас — так, как ему больше «нравится»…
Такая или подобная концепция была бы хороша для какого-нибудь языка программирования, предназначенного для лентяев, не желающих вникать в суть программирования — что-нибудь типа Python и т.п. Но применять подобное решение в учебном языке программирования?! Расчёт на детишек-глупышек, которые всё равно ничего не поймут, а ошибки будут исправлять взрослые? Как говорится, все комментарии (по крайней мере, приличные) — явно неуместны.
В MS Small Basic в принципе отсутствует проверка корректности данных и их преобразований — как явных, так и неявных. В результате мы запросто можем записать вместо числа в переменную кусок текста или, выполнив преобразование число -> текст -> число (или наоборот), получим совсем не то число, которое было в начале.
Можете попробовать, например, создать переменную со значением 345876 (число, да?), а затем определить её длину как текстовой строки (Text.GetLength()) и вы получите — 6! «Чёрт возьми, Холмс! Но как?!…» Ведь это же число! («Логика! Ау?!!!!«)
Приходит в голову только одна логичная (как ни странно!) мысль — писать все (ВООБЩЕ ВСЕ!) константы в программе в кавычках… Но это уже — полный бред! Хотя, наверное, должно сработать… и тем самым вообще уничтожить у учащихся понимание, что такое переменная. А уж про внутреннее представление и возможность записи любого числа в отличных от 10-ичной системах счисления — я вообще молчу!
Если у нас есть две переменных A и B со значениями 3 (число «три») и б0 («бэ» и «ноль» — ну так сложилось: опечатка в файле), то при сложении их в MS Small Basic мы получим 3б0 — нет, не число 360, а строку из трёх символов: «три», «бэ» и «ноль», а при вычитании — получим число «три», потому что текстовая строка, не содержащая чистого числа интерпретируется в MS Small Basic как число 0. И ни единого сообщения об ошибке! Здорово?! И это — учебный язык программирования!
А что делать, если две строки, содержащие числа нужно не сложить, а просто соединить? Ведь для склейки строк в MS Small Basic есть красивая операция «+»… Так вот она — не сработает! Она «тупо» сложит два числа (потому что приоритет сложения выше приоритета склейки). Нет, тут разработчики «вывернулись», придумав функцию гарантированной склейки Text.Append(), однако, создать, например, функцию определения числа — почему-то забыли…
Если же мы захотим вывести число, содержащее десятичную точку в строку, например, используя Text.Append(), то точка «волшебным образом» может «превратиться» в запятую — в зависимости от региональных настроек Windows, и — при «переходе обратно к числу» в программе (переменная-то — одна) — мы вдруг обнаружим, что наше число стало нулём! Потому что в самом MS Small Basic десятичный разделитель — только точка, и, следовательно, строка цифр, содержащая запятую — числом не является, а значит = 0 (по правилам MS Small Basic).
Что можно сделать? Можно аккуратно написать функцию, которая будет пробегаться по всем элементам проверяемой строки (посимвольно) и сравнивать их с цифрами или с десятичной точкой, разумеется, учитывая при этом, что точка в числе может быть только одна. Или можно просто вычитать переменную, проверяемую на число, из нуля: операция «вычитание» со строками не работает, нечисловая строка интерпретируется как число 0, поэтому если результат вычитания останется нулём, то в проверяемой переменной — либо число 0, либо какой-то текст:
' a - проверяемая переменная
If 0 - a = 0 Then
' не число или 0
Else
' число
EndIf
Также, для того, чтобы гарантировать, что у нас точно число, а не текст, на него очень похожий, можно умножать переменную на 1: число не изменится, а строка — превратится в 0. Вроде просто… но глупо до невозможности!
Но… если этого не делать, то в результате сложения можно получить — всё, что угодно! 🙁
Хуже обстоят дела с проверкой переменной на соответствие формату времени или даты: дело в том, что формат задаётся пользователем в настройках Windows и может меняться. Тут видится только один надёжный способ: вывести в какую-нибудь переменную текущие время или дату с помощью функций класса Clock: Date или Time. Затем выполнить посимвольный анализ полученной строки, понимая, что основное содержимое строк — это цифры, а то что между ними — разделители, соответствующие текущему установленному в Windows формату даты или времени. Теперь, основываясь на этих данных анализа, уже можно анализировать любую другую строку на предмет соответствия формату.
А еще в MS Small Basic у нас есть «массивы» с кривой индексацией: индексами массива может быть что угодно, а далеко не только числа. Более того, порядок и следование индексов — вообще не обязательны (это же просто строки!). И если вы, создавая массив, укажете значения для 1, 2 и 4 элементов, пропустив 3-й, то… в вашем массиве будет всего 3 элемента(!), а индексом 3-го (по порядку) элемента будет 4-ка(!): то есть, проходя по массиву циклом For от 1 до 4, вы вообще не встретите элемента с индексом 3(!) — просто потому что его вообще не существует, зато если вы пройдете по массиву циклом For от 1 до длины массива (Array.GetItemCount), то вы никогда не увидите элемента с индексом 4(!), потому что фактическая длина массива — 3. А всё потому, что это не массив в привычном программистском представлении, а просто длинная текстовая строка вида «1=13;2=123;4=98», которая каждый раз(!) обрабатывается специальными функциями текстового поиска и лексического анализа. Ужас? Да не то слово!
И ладно бы еще создали для подобных массивов хотя бы функционал очень удобного оператора цикла ForEach (последовательный перебор по всем существующим элементам массива), существующего во многих современных языках программирования. Действительно, наличие такого инструмента избавило бы от многих проблем при работе с такими вот «умными» массивами. Но нет, на это, к сожалению, чего-то не хватило: то ли квалификации, то ли денег, то ли времени…
Остаётся единственный вариант — принудительная «инициализация» массива перед его использованием или изменением размера — прямой записью в цикле в каждую последовательную ячейку какого-нибудь «начального» значения, например нуля или пробела, что сразу сводит на нет одно из преимуществ такого «умного» массива.
А что MS Small Basic вытворяет со стеками? Если вы используете один стек — вроде всё работает, но стоит вам использовать 2 разных стека (с разными именами) и «инициализировать» их, например, пустыми строками — и эти стеки «волшебным образом» склеятся в один! Поэтому перед первым использованием переменным с именем стека необходимо присваивать какие-то, желательно различные, значения: например, текстовые строки.
Кстати, никого не смутило, что стек нужно инициализировать путем присваивания значения его имени? Тут не то, что о логике — о здравом смысле говорить не приходится!
Только понимание всего вышеизложенного позволит вам избегать в ваших программах на MS Small Basic непонятных и неожиданных результатов и ошибок.
На самом деле «Мелкомягкие» — просто, как обычно, в своём репертуаре:
«Если наши программы на вашем компьютере работают медленно, купите себе более мощный компьютер«.
— Программы работают?
— Да.
— И в чём проблема?
— Медленно работают.
— А нам — плевать! Это — ваша проблема.
Ну действительно, ведь проект-то — бесплатный. Зачем же напрягаться с оптимизацией, осмыслением самого языка?
Как вам, например, такой «перл»: после условия в операторе If обязательно нужен Then, а в операторе While — никакого оператора, закрывающего условие — не предусмотрено! Где тут логика? А ведь это — учебный язык! Ну что стоило хоть как-то упорядочить синтаксис, продумать сам язык до начала программирования?
А библиотеки классов? Возникает ощущение, что кто-то просто резвился — как детёныш шимпанзе в вольере, создавая их: ни логики, ни осмысленности, ни привязки к насущным требованиям — налепили кое-как первое, что в голову пришло: для каких-то задач функционал — откровенной избыточный, а для каких-то его попросту не хватает (и заменить нечем)… Единственная надежда — на библиотеку LitDev, в которой тоже — местами «не все так просто»…
Всё это очень напоминает современные детские книжки, мало того, что написанные откровенно коряво и глупо, так еще и проиллюстрированные так, что впору выставлять иллюстрации на выставке «Творчество душевнобольных».
Такое ощущение, что язык MS Small Basic писался разными студентами кого-то из сотрудников Microsoft второпях: «давай-давай быстрее!» — «сделай как-нибудь, лишь бы работало!» — «надо успеть!» — «бегом-кувырком!»…
Ну что? — «Успели»!… 🙁 Выпустили безусловно очень нужный, но крайне сырой и корявый продукт, который в последствии даже не удосужились доработать.
В итоге получилось как обычно — «хотели как лучше, а получилось — как всегда»: отличная идея разбилась о «скалы» человеческой лени, глупости и жадности. 🙁
Начёт «как обычно» — далеко ходить за примерами не надо: возьмите хоть MS Word, на откровенные баги и кривую логику работы не матерился только ленивый…
Единственный вывод из всего сказанного: на этом языке можно писать что-то серьёзное, только понимая и осознавая все эти нюансы и подводные камни.
А если честно, то что-либо хоть сколько нибудь серьёзное — надо писать на С или С++. Там, по крайней мере, есть уверенность, что программа будет вести себя именно так, как написано — без двусмысленностей и разночтений.
PS:
C момента написания этой статьи прошло уже довольно много времени и MS Small Basic фактически был вытеснен языком Python — языком, вообще непригодным для обучения программированию, однако, никаких попыток хоть как-то исправить возникшую ситуацию: модифицировать Small Basic в сторону качества или заменить его чем-то лучшим — так и не было сделано. Судя по ощущениям, сейчас «из тьмы веков» снова пытается вынырнуть архаичный Pascal — чтобы хоть как-то заткнуть дыру, созданную введением Python’а…
Поделиться: