Типы данных редко попадают в новости, но в декабре 2014 года это случилось из-за клипа Gangnam Style. Ролик набрал больше 2147483647 просмотров. Ровно столько вмещает 32-битное целое число, которым YouTube считал просмотры. Инженеры заранее перевели счётчик на 64-битный формат, иначе цифры под видео просто перестали бы расти. В блоге компании тогда пошутили, что такой популярности никто не ожидал.
У ребёнка, который пишет первую программу, всё выглядит скромнее. Он просит пользователя ввести возраст, прибавляет к нему единицу и получает ошибку. Компьютер не понял, что «15» — это число: для него это два символа текста. Подросток злится на «глупую машину», хотя машина как раз действовала по правилам.
Ниже разбираем, какие типы данных есть почти в любом языке и зачем языки так по-разному за ними следят. А в конце — как помочь ребёнку освоить эту тему без зубрёжки.
Память компьютера состоит из ячеек, в которых хранятся нули и единицы. Одна и та же цепочка битов может означать число 65, латинскую букву A или оттенок пикселя на экране. Сама по себе она ничего не говорит. Смысл ей придаёт тип — пометка о том, как читать содержимое ячейки.
Когда мы объясняем ученикам, что такое тип данных в программировании, используем сравнение со складом. На каждой коробке есть наклейка: «гвозди», «краска», «документы». Наклейка подсказывает, сколько места займёт коробка и что с содержимым можно делать. Гвозди пересчитывают, краску смешивают, документы читают. Смешивать гвозди с документами бессмысленно, и кладовщик это понимает без объяснений.
Хорошо это видно на умножении. Число 7, умноженное на 3, даёт 21. Строку «7» в Пайтоне (Python) тоже можно умножить на 3, но получится «777». Знак операции один и тот же, а поведение разное, и определяет его именно категория значения.
Тип данных влияет и на расход памяти. В Си (C) логическое значение обычно занимает один байт, целое число — четыре, дробное двойной точности — восемь. Для одной переменной разница незаметна. Но игра, которая хранит координаты миллиона частиц, на неверно выбранном типе съест вдвое больше памяти и начнёт тормозить.
Основные типы данных делятся на две группы: простые и составные. Простые хранят одно значение, составные собирают несколько значений вместе. Названия в разных языках отличаются, но набор похож.
Отдельно стоит пустое значение: в Пайтоне это None, в ДжаваСкрипте — null и undefined. Оно означает «здесь пока ничего нет» и тоже относится к своему типу. Если забыть о нём, программа рано или поздно попробует сложить «ничего» с числом.
С дробными числами связан известный сюрприз. Если в Пайтоне сложить 0.1 и 0.2, программа выдаст 0.30000000000000004. Компьютер хранит дроби в двоичном виде, и часть из них записывается лишь приблизительно. Поэтому деньги в банковских системах обычно считают в копейках, то есть целыми числами.
Значения можно переводить из одного вида в другой. Функция int() превращает строку «15» в число 15, str() делает обратное, float() даёт дробное число. Такое преобразование новички забывают чаще всего. Программа просит ввести данные с клавиатуры, а всё, что набрано на клавиатуре, приходит в виде текста.
Классификация в каждом языке своя. В Пайтоне любое значение — объект какого-то класса, и проверить его можно командой type(). В Си (C) целых типов сразу несколько: char, short, int, long. Они различаются объёмом памяти, а значит, и тем, насколько большое число в них поместится. Именно такой предел и упёрся в рекорд Gangnam Style.
Источник: unsplash
Базовые типы данных в популярных языках почти совпадают. Разница в другом: насколько строго язык за ними следит. Это свойство называют типизацией, и у него есть две оси.
Первая ось — когда проверяется тип. При статической типизации тип переменной указывают заранее, и компилятор проверяет код ещё до запуска. Так устроены Си, C++ и Java. При динамической типизации тип становится известен только во время работы программы. Так работают Пайтон и ДжаваСкрипт (JavaScript).
Пайтон останавливает программу и показывает, где проблема. ДжаваСкрипт молча угадывает намерение автора и иногда угадывает неверно. Новичку кажется, что второй вариант удобнее. На практике тихие ошибки искать гораздо дольше, чем громкие.
Цена такой путаницы бывает высокой. В 1996 году ракета «Ариан-5» разрушилась через 37 секунд после старта. Программа навигации попыталась записать 64-битное дробное число в 16-битное целое. Значение не поместилось, система отказала, и ракета сошла с курса. Поэтому многие команды, которые пишут на ДжаваСкрипте, используют TypeScript — его надстройку, где типы указываются явно.
В школьной программе типы данных в информатике появляются вместе с переменными и первыми задачами на программирование. Дальше они всплывают на экзаменах. В ЕГЭ по информатике путаница между делением / и целочисленным делением // легко стоит баллов. В Пайтоне первое всегда возвращает дробное число, даже если 8 делится на 4 без остатка.
В Стартории мы не выносим типы в отдельную лекцию с таблицами. Педагоги-практики разбирают их на задачах, где ошибка видна сразу. Игре нужен счёт — это целое число. Нужно имя игрока — это строка. Флаг «игра окончена» — логическое значение. Когда ребёнок сам решает, какой тип данных выбрать, понятие перестаёт быть абстрактным.
Источник: unsplash
Есть и типичные ошибки, которые мы встречаем у новичков. Ребёнок хранит номер телефона как число и теряет ведущий ноль. Сравнивает строку «10» с числом 10 и удивляется, что они не равны. Считает средний балл через целочисленное деление и получает 4 вместо 4,5. Каждая такая ошибка — повод разобрать тип ещё раз, уже на собственном коде.
Порядок знакомства зависит от возраста. Младшие начинают со Scratch, где переменные уже хранят числа и текст, но язык многое прощает. Подростки переходят к Пайтону, а затем к C++, где тип нужно объявить для каждой переменной. Наша выпускница Ольга в 16 лет написала онлайн-банк на Java. В таком проекте спутать сумму на счёте с текстом недопустимо, и строгая типизация Java помогает это контролировать. Программы для разных возрастов собраны в разделе курсов программирования для детей.
Интуитивно — лет с семи-восьми. В Scratch ребёнок уже видит, что в переменной может лежать число или слово. И быстро замечает, что со словом арифметика не работает. Осознанное понимание приходит позже, обычно в 10–12 лет, когда он переходит на текстовый язык вроде Пайтона. Там ошибки типов появляются в первые же недели, и разбирать их приходится на живых примерах. Торопить этот этап не стоит: важнее, чтобы ребёнок сам объяснил, почему программа сломалась.
Типы данных — это правила, по которым компьютер понимает, что лежит в переменной и что с этим можно делать. Число можно сложить с числом, текст — склеить с текстом, а «да или нет» — проверить в условии. Без этих правил машина не отличит возраст «15» от двух символов на экране. Хорошо работает пример с коробками на складе: наклейка подсказывает, как обращаться с содержимым.
Для старта мы советуем Пайтон. Он строго относится к смешиванию типов и сообщает об ошибке понятным текстом, но не требует объявлять тип у каждой переменной. Так ребёнок видит идею, не утопая в синтаксисе. Си и C++ полезно изучать следом: там становится понятно, как типы связаны с памятью. ДжаваСкрипт нужен тем, кто хочет делать сайты, но новичка его снисходительность к ошибкам скорее запутывает.
Это ошибка несовпадения типов, и новички в Пайтоне сталкиваются с ней постоянно. Самая частая причина — функция input(), которая всегда возвращает строку. Если сложить результат с числом, программа остановится. Исправляется это одним преобразованием: int() превращает строку «15» в число 15. Полезно попросить ребёнка прочитать сообщение об ошибке вслух — в нём обычно прямо написано, какие типы столкнулись.
Переменная — это имя, под которым программа хранит значение, а тип описывает, каким это значение может быть. Если вернуться к складу, переменная — подпись на полке, а тип — наклейка на коробке. В языках со статической типизацией тип закрепляют за переменной навсегда. В Пайтоне тип принадлежит самому значению, поэтому в одну переменную по очереди можно положить и число, и строку. Понимание этой разницы помогает ребёнку читать сообщения об ошибках, а не гадать.
Нужны, причём в практических заданиях, а не в теории. Почти каждая задача на программирование требует понимать, где получится целое число, а где дробное. Ошибки в делении, округлении и преобразовании строк в числа часто стоят баллов даже тем, кто хорошо знает алгоритмы. Чем раньше ребёнок привыкнет думать о типе каждого значения, тем спокойнее пройдёт экзамен.