Найти тему
ZDG

Типы данных: Польза и вред от высокоуровневых языков

В предыдущих частях я пояснял, что простыми типами можно свободно манипулировать, и даже превращать их в указатели и обратно.

Оставалось обсудить сложные типы, кототорые живут в высокоуровневых языках. Высокий уровень – это значит по максимуму cпрятать от нас всю работу с памятью и создать уютный мирок из красивых абстракций, где всё логично, просто и строго. Строго – значит мы будем ограничены почти во всём. За этим будет следить уже сам язык.

Объявили переменную char или String – извольте записывать в неё строго символы. Кроме того, если сложить две переменные символьного типа, то в языке С это будет эквивалентно сложению двух чисел и получится просто какое-то новое число (и какой-то новый символ). Да вот даже натурный эксперимент:

'A' + 'B' = 65+66 = 131 = 'Г'

А в JavaScript или Python получится:

'A' + 'B' = 'AB'

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

"Hello " + "world"

На языке C такая операция просто не имеет смысла, а вот JavaScript и Python спокойно сложат строки и мы получим "Hello world". Правда, чтобы это сделать, им придется выделить память под новую строку и по очереди скопировать в неё содержимое двух исходных строк, так как строки не являются простыми типами. Но это всё будет проделано скрытно от нас, и мы увидим только простой и понятный результат. На то она и высокоуровневость. А в языке C пришлось бы сделать то же самое, но руками и функцией strcpy(). От этого никуда не деться, просто вопрос, кто будет это делать – мы или язык.

Любые массивы, строки, классы и прочее – всё становится самостоятельными, отдельными типами с жестко назначенным для них поведением, которое вы не можете изменить. Менять его и не надо – всё сделано для вашего удобства. В конце концов, складывать строки руками – неудобно.

Массив становится целым классом Array, а что есть у класса? Свойства и методы. Например, возьмем массив в Javascript:

var a = new Array();

Мы создали объект класса Array, и помимо обычного массивного доступа он дает нам возможность пользоваться своими свойствами и методами:

  • a.length - длина массива
  • a.push() - добавить новый элемент в массив
  • a.pop() - удалить элемент из массива
  • a.fill() - заполнить массив чем-то

и многое другое.

По сравнению с обычным массивом это целый звездолет, который дает нам высокий уровень культуры обслуживания.

Но тут появляется и обратная сторона. Чем сильнее вы абстрагируетесь от компьютерной архитектуры, чем больше заворачиваете ваши данные в различные представления и классы, тем больше проблем возникает, когда вам нужна высокая производительность или тонкий доступ к данным. Это критично в том числе и для игр.

Как завести число длиной 1 байт? Никак. Если в JavaScript вы написали:

var a = 5;

У вас нет никакого способа сказать, что это число должно быть байтом. Оно будет таким, каким решит язык.

Если у вас возникает необходимость работать с точной длиной данных, или перегонять числа в символы и обратно, рассмотрите следующие возможности:

  1. Узнайте, какие вспомогательные функции есть в языке. Например, функция char() переводит число в символ. А функция ord() наоборот переводит символ в число. В языке PHP есть функция pack(), которая позволяет построить бинарную строку из данных любого формата.
  2. Узнайте, что умеет сам тип (класс), с которым вы работаете. Если это класс String, то посмотрите, какие у него есть методы (например, charAt(), getBytes() и т.д.) и чем они могут помочь. Может быть и так, что вам надо записать строку задом наперед, а у неё уже есть готовый метод reverse().
  3. Используйте битовые маски для получения нужных вам байт из числа. Например, выражение a & 255 вернёт вам младший байт, а (a >> 8) & 255 – старший.
  4. В последнее время в некоторых языках озаботились производительностью и ввели дополнительные "простые" типы, которые ничем не перегружены. Скажем, в JavaScript это байтовый массив Uint8TypeArray. В Питоне тоже есть нечто подобное. Для повышения производительности по возможности используйте эти типы, а не стандартные.