Недействительные ссылочные типы

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

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

Ответ 1

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

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

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

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

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

Ответ 2

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

Ответ 3

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

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

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

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

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

Этот специальный синтаксис будет неудивительным для программистов на 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:

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

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

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

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

class SpecSharpExampleClass
{
    private string! _nonNullableExampleField;

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

    }
}

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

Ответ 4

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

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

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

Ответ 5

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

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

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

b?->DoSomething();

Чтобы отправить сообщение b, только если оно не равно null.

Ответ 6

Уязвимость должна быть параметром конфигурации, имеющим силу в исходном коде автора. Таким образом, вы позволяете людям, которым нравятся объекты с нулевым значением, по умолчанию пользуются ими в исходном коде, позволяя тем, кто хотел бы, чтобы все их объекты были не нулевыми по умолчанию, имеют именно это. Кроме того, укажите ключевые слова или другое средство для явного определения того, какие из объявлений объявлений и типов могут быть обнуляемыми и которые не могут, с чем-то вроде 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

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

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