Re[2]: C# [Proposal] init block for safe initialization of complex
От: VladD2 Российская Империя www.nemerle.org
Дата: 25.12.25 23:01
Оценка:
Здравствуйте, sergii.p, Вы писали:

Э
SP>почему только локальные функции?

Потому что их проще проанализировать. Они локализованы.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: C# [Proposal] init block for safe initialization of c
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.12.25 05:30
Оценка:
Здравствуйте, 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 как раз и приведён.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Отредактировано 26.12.2025 5:35 Sinclair . Предыдущая версия .
Re[14]: C# [Proposal] init block for safe initialization of
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.12.25 05:32
Оценка:
Здравствуйте, 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
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.12.25 05:35
Оценка:
Здравствуйте, 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
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 26.12.25 07:18
Оценка: :)
Здравствуйте, Sinclair, Вы писали:


S>> Это намного лучше чем городить новый язык, так как может применяться ко всем версиям языка начиная C# 8.0

S>В таком варианте можно попробовать. Хотя конечно меня радует ваше "Написать свой анализатор кода не проблема"

Просим дип сик и многое уже готово!
Ну там немного напильником подчистить
и солнце б утром не вставало, когда бы не было меня
Re[15]: C# [Proposal] init block for safe initialization of
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 26.12.25 07:22
Оценка:
Здравствуйте, 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 так и остались непроинициализированными. Вы код-то попробуйте запустить

Я же уже писал

private Node(bool blin)
{
 this._next= this;
 this._previous = this;
}


Ну и в Next и Previous запрет на изменения для EmptyNode.
и солнце б утром не вставало, когда бы не было меня
Отредактировано 26.12.2025 7:31 Serginio1 . Предыдущая версия .
Re[16]: C# [Proposal] init block for safe initialization of
От: Sinclair Россия https://github.com/evilguest/
Дата: 27.12.25 06:24
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>Здравствуйте, Sinclair, Вы писали:


S>>>>Попробуйте решить проблему при помощи EmptyNode.


S>>У нас проблема не в NullReferenceException, а в нарушении инварианта. В частности, node1.Next и node2.Previous так и остались непроинициализированными. Вы код-то попробуйте запустить


S> Я же уже писал


S>
S>private Node(bool blin)
S>{
S> this._next= this;
S> this._previous = this;
S>}
S>

Это никак не поможет. Вы не понимаете главного: проблема не в null. А в отсутствии инициализации. У нас по ТЗ в графе узлов не должно быть "пустых" ссылок. Неважно, как эти пустые ссылки описываются — как null или как ссылка на специальный синглтон.
И вот ваш код нарушает этот инвариант!
node1.Next == Node.EmptyNode
node1.Previous == node2
node2.Next == node1
node2.Previous == Node.EmptyNode

А должно быть (например)
node1.Next == node2
node1.Previous == node2
node2.Next == node1
node2.Previous == node1

Вот как раз это и надо прогарантировать. И если бы не цикличность топологии, то всё неплохо бы работало и в существующем языке: required как раз и означает, что нужно обязательно проинициализировать эти свойства.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[17]: C# [Proposal] init block for safe initialization of
От: _FRED_ Черногория
Дата: 27.12.25 23:38
Оценка: +2
Здравствуйте, 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
От: _FRED_ Черногория
Дата: 27.12.25 23:48
Оценка: +2 -1
Здравствуйте, VladD2, Вы писали:

VD>https://github.com/dotnet/csharplang/discussions/9903

VD>Прошу поддержать лайком по ссылке (на гитхебе). Ну и приветствуются замечания и предложения.

В целом кажется это можно решить анализатором кода без изменения компилятора:
Help will always be given at Hogwarts to those who ask for it.
Re[17]: C# [Proposal] init block for safe initialization of
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 28.12.25 11:37
Оценка: :)))
Здравствуйте, Sinclair, Вы писали:


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
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 28.12.25 18:05
Оценка:
Здравствуйте, Sinclair, Вы писали:

Антон, а что смешного в

для 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
От: Sinclair Россия https://github.com/evilguest/
Дата: 29.12.25 03:25
Оценка: +2
Здравствуйте, 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
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 29.12.25 07:32
Оценка:
Здравствуйте, Sinclair, Вы писали:


S>> Антон, а что смешного в


S>>

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
От: Sinclair Россия https://github.com/evilguest/
Дата: 29.12.25 13:05
Оценка: +1
Здравствуйте, 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
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 29.12.25 14:51
Оценка:
Здравствуйте, 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
От: Sinclair Россия https://github.com/evilguest/
Дата: 29.12.25 15:03
Оценка:
Здравствуйте, 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
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 29.12.25 15:26
Оценка:
Здравствуйте, 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.Empty
  var 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, но прагма лучше подходит для старых языков. У многих стоит ограничение на фреймворки.
и солнце б утром не вставало, когда бы не было меня
Отредактировано 30.12.2025 9:10 Serginio1 . Предыдущая версия . Еще …
Отредактировано 29.12.2025 15:50 Serginio1 . Предыдущая версия .
Re[24]: C# [Proposal] init block for safe initialization of
От: pilgrim_ Россия  
Дата: 29.12.25 16:39
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>Нет не затыкает! Ибо для крайних узлов это не null!

S>Устал писать. Для последней ноды Next = Node.EmptyNode для первой Previous = Node.EmptyNode

Сергей, такое ощущение что у тебя перед глазами стоит только не циклический двусвязный список, а теперь зацикли его, Как тут в примере у Антона:

node1.Next == node2
node1.Previous == node2
node2.Next == node1
node2.Previous == node1


  Для наглядности возможные графы



Влад в том числе о таких циклах и говорил как я понял (на гитхабе правда пример не дописанный для узлов, но из контекста вроде всё понятно).
Re[25]: C# [Proposal] init block for safe initialization of
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 29.12.25 17:37
Оценка:
Здравствуйте, pilgrim_, Вы писали:


S>>Нет не затыкает! Ибо для крайних узлов это не null!

S>>Устал писать. Для последней ноды Next = Node.EmptyNode для первой Previous = Node.EmptyNode


_>Влад в том числе о таких циклах и говорил как я понял (на гитхабе правда пример не дописанный для узлов, но из контекста вроде всё понятно).


Это классический пример двухнаправленного списка. Или двоичных деревьев.

С полностью циклическими графами я дело не имел. Всегда есть тупики.

У него пример как раз

init (var root = new TreeNode(), var child1 = new TreeNode(), var child2 = new TreeNode())
{
    root.Left = child1;
    root.Right = child2;
    
    SetParent(child1, root);
    SetParent(child2, root);
    
    void SetParent(TreeNode child, TreeNode parent)
    {
        child.Parent = parent; // Parent is a non-nullable property
    }
}


Где для child Left и Right?

Сlass Node
{
    public required Node Next { get; set; }
    public required Node Previous { get; set; }
}

init (var node1 = new Node(), var node2 = new Node())
{
    node1.Next = node2;
    node2.Previous = node1;
}


где для node2.Next и node1.Previous ?


Опять же варианты кода деревья пустые без узлов?
и солнце б утром не вставало, когда бы не было меня
Отредактировано 29.12.2025 18:02 Serginio1 . Предыдущая версия . Еще …
Отредактировано 29.12.2025 17:45 Serginio1 . Предыдущая версия .
Отредактировано 29.12.2025 17:42 Serginio1 . Предыдущая версия .
Отредактировано 29.12.2025 17:38 Serginio1 . Предыдущая версия .
Re[24]: C# [Proposal] init block for safe initialization of
От: Sinclair Россия https://github.com/evilguest/
Дата: 30.12.25 09:06
Оценка: +1
Здравствуйте, 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>


S>
S> void AddNodeToEnd()
S>{
S>  if (LastNode == node.Empty)
S>{
S>   LastNode = new Node(Node.Empty,Node.Empty);
S> FirstNode = LastNode; 
S>}
S>else
S>{
  
S>var node = new Node(LastNode ,LastNode.Next);
S>LastNode.Next = node;
S>LastNode = node;
 
S>}

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, но прагма лучше подходит для старых языков. У многих стоит ограничение на фреймворки.

Прагму сначала нужно спроектировать. Влад, при всех недостатках его идеи, хотя бы внятно изложил а) проблему, б) предлагаемое решение.
У вас же решение на уровне "давайте придумаем какое-нибудь решение". Простите, это несерьёзный разговор. Предложите хоть мало-мальскую спецификацию поведения этой вашей прагмы.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.