Здравствуйте, sergii.p, Вы писали:
SP>то есть вызвать нелокальные функции в обработке property.set он может
Не очень понял, что вы имеете в виду. Можно пример? SP>Или может я не понял, что имеется в виду под локальными функциями? Локальные в модуле, классе, функции?
В примере это локальная функция, объявленная по месту. См. Example 2.
S>>Попробуйте переписать пример с использованием Optional. Станет хуже
SP>переписал. Не вижу, что стало хуже
SP>
SP>using System;
SP>using System.Collections.Generic;
SP>using Optional;
SP>public class Node<T>
SP>{
SP> public required T Value { get; set; }
SP> public Option<Node<T>> Next { get; set; }
SP> public Option<Node<T>> Previous { get; set; }
SP> public Node(T value)
SP> {
SP> Value = value;
SP> Next = Option.None<Node<T>>();
SP> Previous = Option.None<Node<T>>();
SP> }
SP> public static Option<Node<T>> Init<T>(IEnumerable<T> values)
SP> {
SP> using var enumerator = values.GetEnumerator();
SP> if (!enumerator.MoveNext())
SP> return Option.None<Node<T>>();
SP> var head = new Node<T>(enumerator.Current);
SP> var current = head;
SP> while (enumerator.MoveNext())
SP> {
SP> var newNode = new Node<T>(enumerator.Current);
SP> current.Next = Option.Some(newNode);
SP> newNode.Previous = Option.Some(current);
SP> current = newNode;
SP> }
SP> return Option.Some(head);
SP> }
SP> public static IEnumerable<T> TraverseForward<T>(Option<Node<T>> start)
SP> {
SP> var current = start;
SP> while (current.Match(
SP> some: node =>
SP> {
SP> yield return node.Value;
SP> current = node.Next;
SP> return true;
SP> },
SP> none: () => false
SP> )) { }
SP> }
SP>}
SP>
Это означает, что логику проверки на Some/None нужно тащить по всему коду. Если уж этим задуряться, то проверки на null компактнее и лучше читаются:
using System;
using System.Collections.Generic;
public class Node<T>
{
public required T Value { get; set; }
public Node<T>? Next { get; set; }
public Node<T>? Previous { get; set; }
public Node(T value)
{
Value = value;
}
public static Node<T>? Init<T>(IEnumerable<T> values)
{
using var enumerator = values.GetEnumerator();
if (!enumerator.MoveNext())
return null;
var head = new Node<T>(enumerator.Current);
var current = head;
while (enumerator.MoveNext())
{
var newNode = new Node<T>(enumerator.Current);
current.Next = newNode;
newNode.Previous = current;
current = newNode;
}
return Option.Some(head);
}
public static IEnumerable<T> TraverseForward<T>(Node<T>? start)
{
var current = start;
while (current)
{
yield return node.Value;
current = node.Next;
}
}
}
SP>ну вот привёл код выше. Чем секция init будет лучше? Позволит писать компактнее — спорно. Безопаснее — да нисколько.
У вас в коде Init ошибка. Секция init будет лучше тем, что обнаружит её на этапе компиляции. SP>В общем motivation должен быть в виде сравнения. Вот у меня был такой workaround, а вот так получается с init блоком. Второй вариант очевидно лучше по следующим причинам ... Сейчас лично мне совсем не очевидно.
Вроде такой motivation как раз и приведён.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Serginio1, Вы писали:
S>Еще раз #продвинутый nullable enable это анализатор проверки установки свойств S>Он будет выдавать ошибку если не установлены все свойства obj1 и obj2 S>Написать свой анализатор кода не проблема. S>Разумеется основная проверка non-nullable required будет отключена, так за проверку будет отвечать #продвинутый nullable enable
Глобальное отключение non-nullable подорвёт всю идею. S>Если нет отмены то можно и так
S>
S> #nullable disable
S> #продвинутй nullable enable
S> код c проверкой на присваивание всем полям не null значений
S> #продвинутй nullable disable
S> #nullable enable
S>
S> Это намного лучше чем городить новый язык, так как может применяться ко всем версиям языка начиная C# 8.0
В таком варианте можно попробовать. Хотя конечно меня радует ваше "Написать свой анализатор кода не проблема"
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[14]: C# [Proposal] init block for safe initialization of
Здравствуйте, Serginio1, Вы писали:
S>Здравствуйте, Sinclair, Вы писали:
S>>попытка 2: S>>
S>>var node1 = new Node("Hello") { Next = null!, Previous = null! };
S>>var node2 = new Node("World") { Next = node1, Previous = node1) };
S>>node1.Previous = node2;
S>>foreach(var n in Iterate(node1)
S>> Console.WriteLine(n);
S>>
S>>Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
S>>Попробуйте решить проблему при помощи EmptyNode.
S>
S>var node1 = new Node("Hello") { Next = Node.EmptyNode, Previous = Node.EmptyNode };
S>var node2 = new Node("World") { Next = node1, Previous = Node.EmptyNode) };
S>node1.Previous = node2;
S>foreach(var n in Iterate(node1)
S>Console.WriteLine(n);
S>
S>И никаких System.NullReferenceException
Во-первых, вы сначала напишите код Node.EmptyNode
У нас проблема не в NullReferenceException, а в нарушении инварианта. В частности, node1.Next и node2.Previous так и остались непроинициализированными. Вы код-то попробуйте запустить
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[15]: C# [Proposal] init block for safe initialization of
S>> Это намного лучше чем городить новый язык, так как может применяться ко всем версиям языка начиная C# 8.0 S>В таком варианте можно попробовать. Хотя конечно меня радует ваше "Написать свой анализатор кода не проблема"
Просим дип сик и многое уже готово!
Ну там немного напильником подчистить
и солнце б утром не вставало, когда бы не было меня
Re[15]: C# [Proposal] init block for safe initialization of
Здравствуйте, Sinclair, Вы писали:
S>>>Попробуйте решить проблему при помощи EmptyNode.
S>>
S>>var node1 = new Node("Hello") { Next = Node.EmptyNode, Previous = Node.EmptyNode };
S>>var node2 = new Node("World") { Next = node1, Previous = Node.EmptyNode) };
S>>node1.Previous = node2;
S>>foreach(var n in Iterate(node1)
S>>Console.WriteLine(n);
S>>
S>>И никаких System.NullReferenceException S>Во-первых, вы сначала напишите код Node.EmptyNode S>У нас проблема не в NullReferenceException, а в нарушении инварианта. В частности, node1.Next и node2.Previous так и остались непроинициализированными. Вы код-то попробуйте запустить
Здравствуйте, Serginio1, Вы писали:
S>Здравствуйте, Sinclair, Вы писали:
S>>>>Попробуйте решить проблему при помощи EmptyNode.
S>>У нас проблема не в NullReferenceException, а в нарушении инварианта. В частности, node1.Next и node2.Previous так и остались непроинициализированными. Вы код-то попробуйте запустить
S> Я же уже писал
S>
Это никак не поможет. Вы не понимаете главного: проблема не в null. А в отсутствии инициализации. У нас по ТЗ в графе узлов не должно быть "пустых" ссылок. Неважно, как эти пустые ссылки описываются — как null или как ссылка на специальный синглтон.
И вот ваш код нарушает этот инвариант!
Вот как раз это и надо прогарантировать. И если бы не цикличность топологии, то всё неплохо бы работало и в существующем языке: required как раз и означает, что нужно обязательно проинициализировать эти свойства.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[17]: C# [Proposal] init block for safe initialization of
Здравствуйте, Sinclair, Вы писали:
S>Это никак не поможет. Вы не понимаете главного: проблема не в null. А в отсутствии инициализации. У нас по ТЗ в графе узлов не должно быть "пустых" ссылок. Неважно, как эти пустые ссылки описываются — как null или как ссылка на специальный синглтон.
Вот почему мне изначальная идея Влада кажется бесперспективной: не очень понятно (точнее, усложнений потребует) передача init контекста. Например, если часть инициализиции мы захотим сделать в каком-либо методе (чтобы переиспользовать его). Придётся добавить init-модификатор к параметрам. Тогда как альтернатива в виде явного вызова метода валидации не так уж и страшна. А валидация сможет проверить не только то, что все ссылки проинициализтрованны "как-то", а и ещё, например, отсутствие циклов (если нужно) или что-то ещё.
Help will always be given at Hogwarts to those who ask for it.
Re: C# [Proposal] init block for safe initialization of complex
В целом кажется это можно решить анализатором кода без изменения компилятора:
Тип SomeType должен быть отмечен неким атрибутом
Свойства/поля/параметры/возвращаемые значения методов так же, там где это необходимо, размечаются атрибутами, говорящими, что объекты/значения в них могут быть ещё только частично проинициализированны
Как только переменная типа SomeType покидает такой вот "частично проинициализированный" контекст (например возвращается из метода, возвращаемое значение которого атрибутом не размечено), анализатор может проверить, что тип полностью инициализирован.
Help will always be given at Hogwarts to those who ask for it.
Re[17]: C# [Proposal] init block for safe initialization of
S>Это никак не поможет. Вы не понимаете главного: проблема не в null. А в отсутствии инициализации. У нас по ТЗ в графе узлов не должно быть "пустых" ссылок. Неважно, как эти пустые ссылки описываются — как null или как ссылка на специальный синглтон.
S>Вот как раз это и надо прогарантировать. И если бы не цикличность топологии, то всё неплохо бы работало и в существующем языке: required как раз и означает, что нужно обязательно проинициализировать эти свойства.
Это я прекрасно понимаю. Я просто для примера Влада высказал, для not null reference нужны заглушки типам Node.EmptyNode
Опять же ждя первой ноды должно быть Previous = Node.EmptyNode, а для последней Next = Node.EmptyNode
и солнце б утром не вставало, когда бы не было меня
Re[17]: C# [Proposal] init block for safe initialization of
для not null reference нужны заглушки типам Node.EmptyNode
Опять же для первой ноды должно быть Previous = Node.EmptyNode, а для последней Next = Node.EmptyNode
Мы делаем защиту от null, поэтому
public Node<T>? Next { get; set; }
public Node<T>? Previous { get; set; }
Не подходят, так как нужны только для крайних узлов. Во всех других случаях нужно делать проверку инициализации.
Или отключать проверку
#nullable disable
#nullable enable
И продвинутый анализатор тоже будет ругаться на крайние узлы.
Мне больше нравится string.Empty так как в большинстве случаев приходится писать
string.IsNullOrEmpty(str)
вместо
str.IsEmpty
и солнце б утром не вставало, когда бы не было меня
Re[18]: C# [Proposal] init block for safe initialization of
Здравствуйте, Serginio1, Вы писали:
S>Здравствуйте, Sinclair, Вы писали:
S> Антон, а что смешного в
S>
S>для not null reference нужны заглушки типам Node.EmptyNode
S>Опять же для первой ноды должно быть Previous = Node.EmptyNode, а для последней Next = Node.EmptyNode
S> Мы делаем защиту от null, поэтому
То, что мы не делаем защиту от null. Мы делаем защиту от логических ошибок.
Один из видов логических ошибок — недоинициализация. Проблема не в null, а в том, что нужное свойство не получает осмысленного значения. Замена одного бессмысленного значения на другое — это шило на мыло.
Более того, во многих случаях такая замена делает решение хуже. Потому, что ещё сильнее откладывает детектирование проблемы. Null вызывает NRE при первом же обращении, а Empty стрельнет вообще непонятно где. Скорее всего — при проверке результатов работы, и то при условии достаточно внимательной проверки.
А мы хотим, чтобы ошибка обнаруживалась там, где она совершена. Соответственно, not null даст нам ошибку прямо там, где мы пытаемся засунуть null, да ещё и в компайл-тайм, а не при выполнении юнит-теста.
Empty такого преимущества лишён.
S> И продвинутый анализатор тоже будет ругаться на крайние узлы. S>Мне больше нравится string.Empty так как в большинстве случаев приходится писать S>
S>string.IsNullOrEmpty(str)
S>
S>вместо S>
S>str.IsEmpty
S>
Во-первых, нет никакой разницы, что писать — IsNullOrEmpty или IsEmpty.
Если нам надо гарантировать, что в нужное место попадает URL файла, то ни null ни "" нас не устроят.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[19]: C# [Proposal] init block for safe initialization of
S>>для not null reference нужны заглушки типам Node.EmptyNode
S>>Опять же для первой ноды должно быть Previous = Node.EmptyNode, а для последней Next = Node.EmptyNode
S>> Мы делаем защиту от null, поэтому S>То, что мы не делаем защиту от null. Мы делаем защиту от логических ошибок. S>Один из видов логических ошибок — недоинициализация. Проблема не в null, а в том, что нужное свойство не получает осмысленного значения. Замена одного бессмысленного значения на другое — это шило на мыло.
Неее. Нам нужна проверка на полную инициализацию.
И для первой ноды должно быть Previous = Node.EmptyNode, а для последней Next = Node.EmptyNode это осмысленное значение
Но мы получаем проверку компилятора на инициализацию всех свойств.
S>Более того, во многих случаях такая замена делает решение хуже. Потому, что ещё сильнее откладывает детектирование проблемы. Null вызывает NRE при первом же обращении, а Empty стрельнет вообще непонятно где. Скорее всего — при проверке результатов работы, и то при условии достаточно внимательной проверки.
S>А мы хотим, чтобы ошибка обнаруживалась там, где она совершена. Соответственно, not null даст нам ошибку прямо там, где мы пытаемся засунуть null, да ещё и в компайл-тайм, а не при выполнении юнит-теста. S>Empty такого преимущества лишён.
Зато у нас есть проверка на инициализацию свойств, что чего null reference лишен.
Ну а в большинстве проблем для Empty будет бесконечная рекурсия, которая тоже отлавливается.
и солнце б утром не вставало, когда бы не было меня
Re[20]: C# [Proposal] init block for safe initialization of
Здравствуйте, Serginio1, Вы писали:
S> Неее. Нам нужна проверка на полную инициализацию.
Всё верно. S>И для первой ноды должно быть Previous = Node.EmptyNode, а для последней Next = Node.EmptyNode это осмысленное значение
Нет. С чего бы это "осмысленное значение"? Если нас устраивает, что у первой и последней вместо Previous и Next — какой-то булшит, то честнее там так и записать null.
По крайней мере, не будет иллюзии, что они во что-то там проинициализированы.
S> Но мы получаем проверку компилятора на инициализацию всех свойств.
Ничего мы не получаем. Получаем шиш с маслом. Вы можете сколько угодно подменять задачу, но это никак не приближает нас к решению исходной задачи.
Вы делаете, как мои дети: говоришь им "не должно быть мусора на полу" — ну так они его в одёжный шкаф запихивают. "Задача решена".
S>>Более того, во многих случаях такая замена делает решение хуже. Потому, что ещё сильнее откладывает детектирование проблемы. Nul
S> Зато у нас есть проверка на инициализацию свойств, что чего null reference лишен.
Нет никакого "зато". Есть иллюзия, что мы решили задачу. Это как claude, которой пишешь "такой-то тест падает — исправь". А она такая "а, ну да, точно, ведь наша реализация ещё не умеет обрабатывать массивы. Закомментируем тест — ура, все тесты зелёные!" S>Ну а в большинстве проблем для Empty будет бесконечная рекурсия, которая тоже отлавливается.
По-моему, вы надо мной издеваетесь. Раньше нас беспокоила неполная инициализация, которая приводила к NRE при первом обращении. Мы хотели, чтобы неполнота инициализации отлавливалась раньше, желательно прямо в compile time.
Вы предложили заменить дефолтную значение с null на Empty, и теперь неполноту инициализации мы обнаруживаем не раньше, а позже, и ещё менее очевидным образом.
И ещё и настаиваете на своём решении
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[21]: C# [Proposal] init block for safe initialization of
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Serginio1, Вы писали:
S>> Неее. Нам нужна проверка на полную инициализацию. S>Всё верно. S>>И для первой ноды должно быть Previous = Node.EmptyNode, а для последней Next = Node.EmptyNode это осмысленное значение S>Нет. С чего бы это "осмысленное значение"? Если нас устраивает, что у первой и последней вместо Previous и Next — какой-то булшит, то честнее там так и записать null. S>По крайней мере, не будет иллюзии, что они во что-то там проинициализированы.
S>> Но мы получаем проверку компилятора на инициализацию всех свойств. S>Ничего мы не получаем. Получаем шиш с маслом. Вы можете сколько угодно подменять задачу, но это никак не приближает нас к решению исходной задачи. S>Вы делаете, как мои дети: говоришь им "не должно быть мусора на полу" — ну так они его в одёжный шкаф запихивают. "Задача решена".
Получаем. Ибо для всех нод кроме первой и последней у нас будет проверка, а с null у нас этой проверки не будет.
Либо нужно делать
#nullable disable
#nullable enable
S>>>Более того, во многих случаях такая замена делает решение хуже. Потому, что ещё сильнее откладывает детектирование проблемы. Nul
S>> Зато у нас есть проверка на инициализацию свойств, что чего null reference лишен. S>Нет никакого "зато". Есть иллюзия, что мы решили задачу. Это как claude, которой пишешь "такой-то тест падает — исправь". А она такая "а, ну да, точно, ведь наша реализация ещё не умеет обрабатывать массивы. Закомментируем тест — ура, все тесты зелёные!"
Еще раз читай внимательно для всех узлов кроме первой и последней будет "правильная "проверка, чего лишен Node?
S>>Ну а в большинстве проблем для Empty будет бесконечная рекурсия, которая тоже отлавливается. S> S>По-моему, вы надо мной издеваетесь. Раньше нас беспокоила неполная инициализация, которая приводила к NRE при первом обращении. Мы хотели, чтобы неполнота инициализации отлавливалась раньше, желательно прямо в compile time. S>Вы предложили заменить дефолтную значение с null на Empty, и теперь неполноту инициализации мы обнаруживаем не раньше, а позже, и ещё менее очевидным образом. S>И ещё и настаиваете на своём решении
Меня беспокоило то, что в алгоритме Влада будет вызываться ошибка, так как первый и последний узел не будут инициализироваться!
Я предложил , что не нужно изменять язык, достаточно добавить свой анализатор типа
#nullable disable
#продвинутй nullable enable
код c проверкой на присваивание всем полям не null значений
#продвинутй nullable disable
#nullable enable
Ну или
#nullable disable
#pragma warning restore продвинутый nullable
код c проверкой на присваивание всем полям не null значений
#pragma warning disable продвинутый nullable
#nullable enable
и солнце б утром не вставало, когда бы не было меня
Re[22]: C# [Proposal] init block for safe initialization of
Здравствуйте, Serginio1, Вы писали:
S> Получаем. Ибо для всех нод кроме первой и последней у нас будет проверка, а с null у нас этой проверки не будет.
Нет. Ни для какой из нод никакой проверки нет.
То, что вы кому-то из них что-то установили, никак не контролируется компилятором.
Вот код — ошибка копипаста:
var node1 = new Node("Hello") { Next = Node.EmptyNode, Previous = Node.EmptyNode };
var node2 = new Node("World") { Next = node1, Previous = Node.EmptyNode) };
node1.Previous = node2;
foreach(var n in Iterate(node1)
Console.WriteLine(n);
Компилятор молчит. Дальше что? Где проверка-то?
S> Еще раз читай внимательно для всех узлов кроме первой и последней будет "правильная "проверка, чего лишен Node?
Сколько бы раз я не читал, неправда правдой быть не перестанет. Проверка либо есть, либо её нету. EmptyNode проверку затыкает — ничуть не лучше, чем null!.
S>Меня беспокоило то, что в алгоритме Влада будет вызываться ошибка, так как первый и последний узел не будут инициализироваться!
Ну так и в вашем коде они не инициализируются.
S>Я предложил , что не нужно изменять язык, достаточно добавить свой анализатор типа
Ну так Влад примерно это и предлагает. Только встроить "анализатор" в компилятор, где уже процентов 70% этого анализа проведено. Плюс есть ещё несколько интересных вопросов про то, как должен этот анализатор выяснять, что именно ему нужно проверить. Влад пытался навелосипедить специальный стейтмент, который позволяет указать границы "опасной зоны" вместе с конкретными объектами, которые нужно доинициализировать в её пределах. А как прагма поможет понять, за кем следить? Что, если прагмы будут стоять не по границам C# scope?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[23]: C# [Proposal] init block for safe initialization of
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Serginio1, Вы писали:
S>> Получаем. Ибо для всех нод кроме первой и последней у нас будет проверка, а с null у нас этой проверки не будет. S>Нет. Ни для какой из нод никакой проверки нет. S>То, что вы кому-то из них что-то установили, никак не контролируется компилятором.
S>Вот код — ошибка копипаста: S>
S>var node1 = new Node("Hello") { Next = Node.EmptyNode, Previous = Node.EmptyNode };
S>var node2 = new Node("World") { Next = node1, Previous = Node.EmptyNode) };
S>node1.Previous = node2;
S>foreach(var n in Iterate(node1)
S> Console.WriteLine(n);
S>
S>Компилятор молчит. Дальше что? Где проверка-то?
Это просто набросок. По уму нужно делать проверку на первый и последний узел который будет у родителя. А именно.
void AddBeforeNode(Node node)
{
if (node == FirstNode) // if (node.Previous == Node.Empty)
{
var node = new Node(Node.Empty,node);
}
else
{
// Вернее этот код будет работать и для первой ноды так как node.Previous == Node.Emptyvar node = new Node(node.Previous ,node);
node.Previous.Next = node;
}
node.Previous = node;
}
void AddNodeToEnd()
{
if (LastNode == node.Empty)
{
LastNode = new Node(Node.Empty,Node.Empty);
FirstNode = LastNode;
}
else
{
var node = new Node(LastNode ,LastNode.Next);
LastNode.Next = node;
LastNode = node;
}
}
S>> Еще раз читай внимательно для всех узлов кроме первой и последней будет "правильная "проверка, чего лишен Node? S>Сколько бы раз я не читал, неправда правдой быть не перестанет. Проверка либо есть, либо её нету. EmptyNode проверку затыкает — ничуть не лучше, чем null!.
Нет не затыкает! Ибо для крайних узлов это не null! S>>Меня беспокоило то, что в алгоритме Влада будет вызываться ошибка, так как первый и последний узел не будут инициализироваться! S>Ну так и в вашем коде они не инициализируются.
Устал писать. Для последней ноды Next = Node.EmptyNode для первой Previous = Node.EmptyNode
S>var node2 = new Node("World") { Next = node1, Previous = Node.EmptyNode
S>>Я предложил , что не нужно изменять язык, достаточно добавить свой анализатор типа
S>Ну так Влад примерно это и предлагает. Только встроить "анализатор" в компилятор, где уже процентов 70% этого анализа проведено. Плюс есть ещё несколько интересных вопросов про то, как должен этот анализатор выяснять, что именно ему нужно проверить. Влад пытался навелосипедить специальный стейтмент, который позволяет указать границы "опасной зоны" вместе с конкретными объектами, которые нужно доинициализировать в её пределах. А как прагма поможет понять, за кем следить? Что, если прагмы будут стоять не по границам C# scope?
Значит будет смотреть все переменные в прагме, как это делается для всех прагм.
Возможно и стоит сделать для нового языка этот init, но прагма лучше подходит для старых языков. У многих стоит ограничение на фреймворки.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали: S>Нет не затыкает! Ибо для крайних узлов это не null! S>Устал писать. Для последней ноды Next = Node.EmptyNode для первой Previous = Node.EmptyNode
Сергей, такое ощущение что у тебя перед глазами стоит только не циклический двусвязный список, а теперь зацикли его, Как тут в примере у Антона:
Здравствуйте, Serginio1, Вы писали:
S>Это просто набросок. S>По уму нужно делать проверку на первый и последний узел который будет у родителя. А именно.
S>
S> void AddBeforeNode(Node node)
S>{
S> if (node == FirstNode) // if (node.Previous == Node.Empty)
S>{
S> var node = new Node(Node.Empty,node);
S>}
S> else
S>{
S>// Вернее этот код будет работать и для первой ноды так как node.Previous == Node.Empty
S> var node = new Node(node.Previous ,node);
S>}
S>node.Previous = node;
S>}
S>
Что это вообще? Что за if? Что за методы? Кто такие FirstNode и LastNode?
Если вы не приучите себя к дисциплине написания связного текста на естественных языках и языках программирования, то в голове будет такая же каша, как в ваших постах в этом топике.
S>Нет не затыкает! Ибо для крайних узлов это не null!
Ну как же не затыкает — компилятор перестал жаловаться, а в коде по-прежнему ошибка.
S>Устал писать. Для последней ноды Next = Node.EmptyNode для первой Previous = Node.EmptyNode
Я и так это вижу. Вы, похоже, не понимаете, что в этом и есть проблема.
У нас НЕ БЫЛО задачи сделать "Для последней ноды Next = Node.EmptyNode для первой Previous = Node.EmptyNode". У нас была задача "обеспечить, чтобы у каждого узла были валидные Next и Previous узлы".
Вы заменили невалидный null (засунутый туда при помощи null! сквозь сжатые зубы компилятора) на невалидный Node.EmptyNode.
Пока вы не поймете, что вы так не решаете, а усугубляете проблему, толку не будет.
S>Значит будет смотреть все переменные в прагме, как это делается для всех прагм.
Что такое "все переменные в прагме"? Явно продекларированные? Все, включая темпоралы? Что насчёт неявно типизированных выражений вроде tuple initializer?
S>Возможно и стоит сделать для нового языка этот init, но прагма лучше подходит для старых языков. У многих стоит ограничение на фреймворки.
Прагму сначала нужно спроектировать. Влад, при всех недостатках его идеи, хотя бы внятно изложил а) проблему, б) предлагаемое решение.
У вас же решение на уровне "давайте придумаем какое-нибудь решение". Простите, это несерьёзный разговор. Предложите хоть мало-мальскую спецификацию поведения этой вашей прагмы.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.