Ненулевые ссылочные типы

Я разрабатываю язык, и мне интересно, разумно ли делать ссылочные типы ненулевыми по умолчанию и использовать "?"для nullable значений и ссылочных типов. Есть какие-то проблемы? Что бы вы сделали по этому поводу:

class Foo {
    Bar? b;
    Bar b2;
    Foo() {
        b.DoSomething(); //valid, but will cause exception
        b2.DoSomething(); //?
    }
}

7 ответов


моя нынешняя философия языкового дизайна заключается в том, что nullability должен быть чем - то, что программист вынужден просить, а не по умолчанию для ссылочных типов (в этом я согласен с Тони Хоаром-Google для его недавнего разговора QCon).

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

мой девиз достаточно прост. Ссылки на литературу являются косвенным дескриптором некоторого ресурса, который мы можем пройти, чтобы получить доступ к этому ресурсу. Значение null ссылки или косвенный дескриптор ресурса,или уведомление о том, что ресурс недоступен, и никто никогда не уверен, что семантика используется. Это дает либо множество проверок спереди (это null? Нет? Ура!), или неизбежный NPE (или эквивалент). Большинство программных ресурсов в наши дни не являются массовыми ресурсами ограниченные или привязанные к некоторой конечной базовой модели - нулевые ссылки, упрощенно, являются одним из...

  • лень: "я просто забью нуль здесь". Что, честно говоря, я не слишком сочувствую
  • путаница: "я еще не знаю, что здесь положить". Как правило, также наследие старых языков, где вам нужно было объявить имена ресурсов, прежде чем вы узнали, каковы ваши ресурсы.
  • ошибки:"это пошло не так, вот NULL". Лучшая ошибка таким образом, механизмы отчетности имеют важное значение на языке
  • отверстие: "я знаю, что скоро у меня что-то будет, дайте мне заполнитель". Это имеет больше достоинств, и мы можем подумать о способах борьбы с этим.

конечно, решение каждого из случаев, которые NULL current обслуживает с лучшим лингвистическим выбором, не является небольшим подвигом и может добавить больше путаницы, что это помогает. Мы всегда можем перейти к неизменяемым ресурсам, поэтому NULL в нем только полезные состояния (ошибка и отверстие) не очень реальны использовать. Императивные technqiues здесь, чтобы остаться, хотя, и я откровенно рад - это делает поиск лучших решений в этом пространстве стоит.


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


эта функция была в Spec#. Они по умолчанию аннулируются ссылки и используются ! чтобы указать не nullables. Это было потому, что они хотели обратной совместимости.

на языке моей мечты (из которых я, вероятно, буду единственным пользователем!) Я бы сделал тот же выбор, что и вы, не аннулируемый по умолчанию.

я бы также сделал незаконным использование . оператор на ссылку, допускающий значение null (или что-нибудь еще, что бы разыменовать его). Как бы вы их использовали? Ты сначала нужно преобразовать их в ненулевые. Как бы ты это сделал? Проверяя их на null.

в Java и C#if заявление может принять только bool проверяемое выражение. Я бы расширил его, чтобы принять имя нулевой ссылочной переменной:

if (myObj)
{
    // in this scope, myObj is non-nullable, so can be used
}

этот специальный синтаксис не удивил бы программистов на C/C++. Я бы предпочел специальный синтаксис, как это, чтобы дать понять, что мы делаем проверку, которая изменяет тип имени myObj в правда-ветвь.

я бы добавил еще немного сахара:

if (SomeMethodReturningANullable() into anotherObj)
{
    // anotherObj is non-nullable, so can be used
}

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

я бы сделал то же самое для ?: оператора.

string message = GetMessage() into m ? m : "No message available"; 

отметим, что string message не имеет значения null, но таковы два возможных результата теста выше, поэтому присвоение значения.

и тогда, может быть, немного сахара для предположительно распространенного случая замены значения на null:

string message = GetMessage() or "No message available";

очевидно or будет применяться только к типу nullable с левой стороны и не-nullable с правой стороны.

(у меня также было бы встроенное понятие собственности, например, полей; компилятор будет генерировать IDisposable.Dispose метод автоматически, и ~Destructor синтаксис будет использоваться для увеличения Dispose, точно так же, как в C++/CLI.)

Spec# had другое синтаксическое расширение, связанное с не-nullables, из-за проблемы обеспечения того, чтобы не-nullables были правильно инициализированы во время построения:

class SpecSharpExampleClass
{
    private string! _nonNullableExampleField;

    public SpecSharpExampleClass(string s)
        : _nonNullableExampleField(s) 
    {

    }
}

другими словами, вы должны инициализировать поля так же, как и другие конструкторы с base или this - если, конечно, вы не инициализируете их непосредственно рядом с объявлением поля.


посмотреть оператор Элвис предложение для Java 7. Это делает что-то подобное, поскольку он инкапсулирует проверку null и метод dispatch в одном операторе с указанным возвращаемым значением, если объект равен null. Таким образом:

String s = mayBeNull?.toString() ?: "null";

проверяет, является ли строка s нулевой, и возвращает строку "null", если да, и значение строки, если нет. Возможно, пища для размышлений.


несколько примеров подобных функций на других языках:

там же Nullable<T> (из C#), но это не такой хороший пример из-за различной обработки типов ссылок и значений.

в вашем примере вы можете добавить оператор отправки условного сообщения, например

b?->DoSomething();

отправить сообщение b только если это не-null.


имеют nullability быть настройкой конфигурации, принудительно в исходном авторов код. Таким образом, вы позволите людям, которым по умолчанию нравятся объекты nullable, пользоваться ими в исходном коде, а тем, кто хотел бы, чтобы все их объекты были не-nullable по умолчанию, именно это. Кроме того, укажите ключевые слова или другое средство, чтобы явно отметить, какие из ваших объявлений объектов и типов могут быть аннулированы, а какие не могут, с чем-то вроде nullable и not-nullable, чтобы переопределить глобальные значения по умолчанию.

например

/// "translation unit 1"

#set nullable
{ /// Scope of default override, making all declarations within the scope nullable implicitly
     Bar bar; /// Can be null
     non-null Foo foo; /// Overriden, cannot be null
     nullable FooBar foobar; /// Overriden, can be null, even without the scope definition above 
}

/// Same style for opposite

/// ...

/// Top-bottom, until reset by scoped-setting or simply reset to another value
#set nullable;

/// Nullable types implicitly

#clear nullable;

/// Can also use '#set nullable = false' or '#set not-nullable = true'. Ugly, but human mind is a very original, mhm, thing.

многие люди утверждают, что дать всем то, что они хотят, невозможно, но если вы разрабатываете новый язык, попробуйте новые вещи. Тони хор представил концепцию null в 1965 году, потому что он не мог устоять (его собственные слова), и мы платим за это с тех пор (также, его собственные слова, человек сожалеет об этом). Смысл в том, что умные, опытные люди совершают ошибки, которые стоят всем нам, не так ли? примите любой совет на этой странице, как будто это единственная правда, включая мою. Оцените и подумайте об этом.

Я прочитал много много разглагольствований о том, как это мы, бедные неопытные программисты, которые действительно не понимают, где действительно использовать null а где нет, показывая нам узоры и антипаттерны, которые предназначены для предотвращения стрельбы в ногу. Все это время миллионы еще неопытных программистов производят больше кода на языках, которые позволяют null. Я!--7-->может будь неопытный, но я знаю, какой из моих объектов не выигрывает от того, что он недействителен.


Я думаю, что нулевые значения хороши: они являются четким признаком того, что вы сделали что-то неправильно. Если вы не инициализируете ссылку где-то, вы получите немедленное уведомление.

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