Статьи

Что если каждый объект был массивом? Нет больше исключений NullPointerException!

NULL или нет NULL? Дизайнеры языка программирования неизбежно должны решить, поддерживают ли они NULL или нет. И они доказали, что им трудно понять это правильно. NULL не является интуитивно понятным ни в одном языке, поскольку NULL является аксиомой этого языка, а не правилом, которое может быть выведено из аксиом более низкого уровня. Возьмите Java, например, где

// This yields true:
null == null

// These throw an exception (or cannot be compiled)
null.toString();
int value = (Integer) null;

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

В то же время SQL не знает результатов «NULL», только значения «NULL». С точки зрения теории множеств существуют только  пустые множества , а не множества NULL.

Другие языки допускают разыменование null через специальные операторы, позволяя компилятору генерировать утомительные проверки нуля для вас, за кулисами. Примером этого является Groovy с его  нулевым безопасным оператором разыменования . Это решение далеко от общепринятого, как можно увидеть в этом обсуждении об эквивалентах Scala . Scala использует  Option , которую Java 8 будет имитировать, используя  Optional  (или  @Nullable ).

Давайте подумаем о гораздо более широком решении

Для меня обнуляемость не первоклассный гражданин. Мне лично не нравится тот факт, что тип Option [T] в Scala загрязняет мою систему типов, вводя универсальный тип-обертку (даже если кажется, что он реализует аналогичные функции массива через  проходимую черту ). Я не хочу различать типы Option [T] и T. Это особенно верно, когда рассуждаю о типах с точки зрения API отражения, где наследие Scala (и Java) навсегда лишит меня доступа к типу T во время выполнения ,

Но гораздо хуже, в большинстве случаев, в моем приложении я действительно не хочу различать ссылки «опции» и «некоторые» ссылки. Черт возьми, я даже не хочу отличать одну ссылку от десятка. JQuery  понял это совершенно правильно. Одна из основных причин популярности jQuery заключается в том, что все, что вы делаете, вы делаете на наборе обернутых элементов DOM. API никогда не различает соответствие 1 или 100 делений. Проверьте следующий код:

// This clearly operates on a single object or none
$('div#unique-id').html('new content')
                  .click(function() { ... });

// This possibly operates on several objects or none
$('div.any-class').html('new content')
                  .click(function() { ... });

Это возможно, потому что JavaScript позволяет переопределять прототип типа JavaScript Array, изменяя массивы в целом, по крайней мере, для области видимости библиотеки jQuery. Насколько более удивительным это может стать? .html () и .click () — это действия, выполняемые над массивом в целом, независимо от того, имеется ли в вашем совпадении ноль, один или 100 элементов. Как будет выглядеть более безопасный язык, когда все будет вести   себя как массив (или ArrayList)? Подумайте о следующей модели:

class Customer {
  String firstNames;  // Read as String[] firstNames
  String lastName;    // Read as String[] lastName
  Order orders;       // Read as Order[] orders
}

class Order {
  int value;          // Read as int[] value
  boolean shipped() { // Read as boolean[] shipped
  }
}

Не ругайте (только пока). Давайте предположим, что это не приведет к накладным расходам памяти или вычислениям. Давайте продолжим думать о преимуществах этого. Итак, я хочу посмотреть, были ли отправлены заказы Клиента. Легко:

Customer customer = // ...
boolean shipped = customer.orders.shipped();

Это не выглядит впечатляюще (пока). Но остерегайтесь того факта, что у клиента может быть несколько заказов, и вышеупомянутая проверка действительно проверяет, все ли заказы были отправлены. Я действительно не хочу писать цикл, я считаю совершенно очевидным, что я хочу выполнять проверку shipped () для каждого заказа. Рассматривать:

// The length pseudo-field would still be
// present on orders
customer.orders.length;

// In fact, the length pseudo-field is also
// present on customer, in case there are several
customer.length;

// Let's add an order to the customer:
customer.orders.add(new Order());

// Let's reset order
customer.orders.clear();

// Let's calculate the sum of all values
// OO-style:
customer.orders.value.sum();
// Functional style:
sum(customer.orders.value);

Конечно, будет несколько предостережений, и приведенный выше выбор имен методов может оказаться не лучшим. Но способность иметь дело с одиночными ссылками (обнуляемыми или ненулевыми) или ссылками на массивы (пустыми, однозначными, многозначными) одним и тем же синтаксическим способом — это просто чистая синтаксическая удивительность. Нулевые проверки будут заменены проверками длины, но в большинстве случаев вам даже не нужно это делать, потому что каждый метод всегда вызывается для  каждого  элемента в массиве. Нынешняя семантика одиночной ссылки и многократной ссылки будет задокументирована соглашениями об именах. Очевидно, что присвоение имени «заказам» означает, что множественные ссылки возможны, тогда как присвоение имени «заказчику» означает, что множественные ссылки маловероятны.

Как прокомментировали пользователи, этот метод обычно называется  программированием массива , который реализован в Matlab или R.

Будучи убеждена?

Мне любопытно услышать ваши мысли!