Blitzmax
Пятница, 03.05.2024, 05:39
Приветствую Вас Гость | RSS
 
Главная СтатьиРегистрацияВход
Меню сайта
Категории каталога
Разное [2]
BlitzMax [5]
Доки/Уроки [8]
Игровое программирование [1]
Наш опрос
Оцените скорость работы с сайтом
Всего ответов: 112
Главная » Статьи » BlitzMax

Неприятное в BlitzMax, ч.1 - язык

1.1. Отсутствие перегрузки функций. Это большое зло. Это надо, это сокращает время для написания кода. Плюс этот недостаток порождает целый ряд других.
Пример:
Нужен менеджер ресурсов. Там нужен такой метод LoadRes(target:TypeOfResource var, url$). Вот при перегрузке функций, нужная функция в зависимости от типа нужного ресурса будет подставляться на этапе сборки. А без перегрузки я должен: первое - писать свой обработчик по типу ресурса (если сделать одну функцию с параметром типа общего объекта - Object) - тратить свое время на лишний код! И второе - этот код будет выполняться во время работы процесса, что будет снижать быстродействие! Уже два ОГРОМЕННЫХ МИНУСА!
Можно обойти это немного, конкретизировав методы загрузки ( LoadImage(url$), LoadSound(url$) ), но это немного снизит удобство. Т.к. для каждого ресурса надо будет помнить свою функцию.

1.2. Отсутствие конструкторов с параметрами. Писать функции для создания классов - не очень то и удобно с точки зрения поддержки и развития кода. - Их ведь нельзя наследовать и п1 - нельзя перегружать. Делать для инициализации статические методы (тоже что и функции по сути) при наличии потомков - тоже неудачно и упирается в отсутствие перегрузки функций и методов - см.сл.п.

1.3. Неправильная или глючная поддержка в потомках возвращаемых значений методов. Т.е. в потомке нельзя переопределить тип возвращаемого значения. Оно логично со второго раза, а с третьего - видно, что не менее логично, если тип возвращаемого значения - объект, то в методе потомка можно возвращать потомка от исходного значения-объекта. Чем плохо конкретно - тем, что нельзя писать одноименные методы-конструкторы для потомков и предков красиво и без извратов (приведения типов, что делает код громоздким и невыразительным). А так же методы копирования. Т.е., по сути, нет перегрузки методов (и функций), что неудобно.

1.4. Невозможность создания указателей на типы пользователя. Например я сделал тип TRGBA_Color с полями R, G, В, и А соответсвенно для цветов и прозрачности. Сделать так я не могу:
Local p:TRGBA_Color Ptr = TRGBA_Color Ptr(bmp.PixelPtr(0,0))
Т.е. получить указатель на пикселы и работать с ним красиво - p.R = 100. Приходится делать это указателем на байты, что с ЯП высокого уровня не очень то и ассоциируется. Похоже, это связано с тем, что каждый тип является объектом и переменная этого типа уже и есть указатель на объект и заботой о защите памяти (только safe - функционал). Приведение типов или индексный доступ, конечно, не защищены от "дурака" - прогламмера (unsafe - функционал), но позволяют "не дураку" нормально и удобно работать.

1.5. Нет команды SinCos, которая поддерживается новыми процессорами и позволяет быстрее производить операции просчета вращения и т.п., т.к. обычно надо и синус и косинус угла, а одной командой это явно сделать быстрее, чем двумя.

1.6.Статический step в циклах. Иногда надо, чтобы при проходе по массиву приращение индекса менялось. Приходится делать через while/wend.

1.7. Нет оператора With. Можно сделать аналог, но это увеличивает громоздкость кода.

1.8. Система слежения за освободившейся памятью (менеджер памяти языка) и автоматическим удалением не нужных уже объектов, хоть и хороша и удобна, но не совершенна. И порой возникали утечки из-за перекрестных ссылок (кросслинков). Т.е. все равно приходится следить за корректной очисткой памяти, что отвлекает от основного процесса написания кода, увеличивает объем текста программы и в сумме эти два фактора приводят к увеличению времени написания программы. Плюс это не характерно для ЯП высокого уровня - менеджер памяти должен быть на высоте. Так что это получается что-то среднее между ЯП высокого и среднего уровней.
Утечки возникают даже не при кросс-линках а и в ситуациях, когда возникать не должны. Например: объект-контейнер, содержит в себе список других объектов. Объекты содержат поле с линком на элемент списка типа TLink, - не на сам контейнер. На этот контейнер ссылается глобальная переменная, поэтому он и "живет". Глюк: если в методе объекта из списка контейнера глобальная переменная переопределяется (в "пусто" или другой контейнер), то память не очищается! Контейнер не удаляется! При освобождении объекта в другом месте - все нормально и память освобождается. Глюк лечится, если объект из контейнера при переопределении глобальной переменной выбрасывается из списка - Tlink.Remove(). Но вообще-то такого быть не должно.

1.9. Нет указателей на методы типов. Указатели на функции - есть, а на методы - нет. А это облегчило бы написание кода в некоторых случаях.

1.10. Нет нормальной полноценной совместимости (приведения) типов. Неоднократно сталкивался с тем, что надо было массив TObject[] преобразовать к моему типу (например для возврата из функции, для конвертирования из TList к массиву). Приходилось писать свои функции для преобразования вроде ObjArrayToTMytypeArray: TMytype[]( Object[] ). Можно в принципе и без этого - приводить типы уже во время работы с массивом, но наглядность и легкость чтения кода теряются. А это надо для реюзабельности кода.
П.с.: Таки сделали приведение типов для массивов - хорошо хоть развивается язык, а не стоит на месте.
П.п.с.: Млин. Криво работает. Нулевые массивы на выходе часто.

1.11. Нет директивы inline. Нужна она! И не только для ускорения работы кода.

1.12. Глюк с продолжением строки: если второй строкой идет комментарий, то выдается ошибка:
Field pms:TPixmap[] = [ ..
'LoadImage("images/gem_1_rotate.png") ..
- это нужно для комментирования при экспериментах с различными значениями в массиве.

1.13. Оптимизация кода очень плохая. Нет оптимизации по использованию методов - методы, которые ни разу не использовались в коде, все равно компилируются. Тот код, который пишется, буквально переводится один в один.

1.14. Нет инкапсуляции, т.е. защищенных и открытых методов и полей класса. Есть ее какое-то подобие на уровне модуля, но не в классе. А отсутствие инкапсуляции - это есть unsafe.

1.15. Нет автоматического приведения типов. Т.е. если в функции объявлен один тип, а передается другой, причем совместимый (общий класс Object), возникает ошибка.

1.16. Игры с типами не доделаны. Вот начал я привыкать к этим играм с типизацией и ощутил необходимость ссылки на тип. То, что в С++ шаблонами можно сделать. Такая переменная в которой нужный тип обозначен - очень нужно для наследования и для различных фабрик объектов, чтоб кода писать меньше. А то можно и приустать конструкторы под каждый новый тип переписывать, раз уж нет их с параметрами и перегрузки функций тоже нет.
П.с.: !!! Я придумал, как это обойти. В нужных нам классах метод Copy(), создающий копию класса. Неужели сделали перегрузку хоть на уровне преобразования возвращаемого результата с учетом наследования. Но - нужно самому писать весь код по копированию.
С версии 1.26 введен механизм отражений, который ввел тип
TTypeId, который и является описанием типа или ссылкой на тип.

1.17. Нет автоматических конструкторов копирования объектов. Приходится писать самому - а это время. А время - деньги.

1.18. Несколько глупо реализовано конструирование объектов при наследовании. Переопределенный конструктор предка вызывается по любому, даже если мы его не вызываем и его вызов нам не нужен, т.к. мы переопределяем конструктор в наследнике.
Практический пример: нужно незначительное изменение предка. Предок использует поле объекта одного типа, в наследнике нужно это же поле, но другого типа. В конструкторе этот объект создается. В наследнике значит надо переопределить создание этого объекта на нужный нам тип. Но в конструкторе предка этот объект тоже создается, а потом пересоздается в наследнике. Конечно, менеджер памяти лишний объект потом удалит, но вообще получается очень глупое и неразумное использование ресурсов. Хорошо если этот объект маленький, а если требует серьезных расчетов, подгрузки ресурсов и т.д. - получится заметное снижение производительности. Поэтому предок надо писать заново либо с нуля, либо с предка предка, еще не имеющего нужных нам полей объектов. Вывод: Язык не очень дружелюбен к наследованию и, следовательно, к хорошей поддержке крупных и долгосрочных проектов.

1.19. Нет макросов и шаблонов. Хотя бы макросы блин – это уже несколько заменило бы шаблоны. А нужно это чтобы не писать кучу однотипного кода с небольшими вариациями. Это бы прилично сократило время на набор текстов программ.

1.20.Переопределение полей в наследниках. Считаю это небезопастным свойством языка. Дело в том, что не выдается никаких сообщений при компиляции по поводу переопределения полей. И можно при последующей доработке класса, нечаянно переопределить какое-либо существующее поле, что приведет к ошибкам в работе логики программы. И уж если нельзя делать перегрузку и переопределение методов в наследниках, то, почему это можно в отношении полей? - Нарушается внутренняя логика языка.

1.21. Компилятор и конечный код - просто ужасны. Я молчу про оптимизацию, элементарные вещи делаются через объездые пути. Пример:
Простейшая функция:
function _RDT:long()
    return 111
endfunction

Сгенерированный Blitzmax код:
    push    ebp
    mov    ebp,esp
    sub    esp,8
    mov    edx,dword [ebp+8]
    mov    dword [ebp-8],111
    mov    dword [ebp-4],0
_3:
    mov    eax,dword [ebp-8]
    mov    dword [edx],eax
    mov    eax,dword [ebp-4]
    mov    dword [edx+4],eax
    mov    esp,ebp
    pop    ebp
    ret

Это же просто ужас. Зачем метка внутри? - она не используется. Зачем отнимается от указателя стека 8 в начале? Что за манипуляции с ним между BP и DX?  И вот аналогичный нормальный код, выполняющий ту-же задачу:
        push    ebp
        mov     ebp,dword[esp+8]
        mov     dword [ebp],111
        mov     dword [ebp+4],0
        pop     ebp
        ret

Ну что тут можно написать? - Отстой! (А что вы хотели за 10 копеек всего? Юнити - тру!)

1.22. Нет поддержки событий. События - это хорошо! Их поддержка быть должна. Можно конечно и без них и даже с ними, если самому либу написать. Но в правильных языках это есть. Это кстати пересекается с п 1.9 - Нет указателей на методы. Чтоб нормально работать с событиями - они должны быть. И с нормальным синтаксисом, а не как в С++. Можно, конечно, через отражения сделать - но это ж как неэффективно, плюс ошибки во время работы, а не на этапе компиляции - нехорошо это. Однозначно!

Другие материалы по теме


Источник: http://bmax-ru.blogspot.com/2007/06/blitzmax-1.html
Категория: BlitzMax | Добавил: oxid (02.07.2007) | Автор: oxid
Просмотров: 3717 | Рейтинг: 0.0/0 |

Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Форма входа
Поиск
Ссылки
Статистика
Copyright Oxid © 2024
Сайт создан в системе uCoz