C# 8 - фича №1
От: Shmj Ниоткуда  
Дата: 03.12.19 07:48
Оценка:
Что из этого списка вы бы назвали наиболее важным и полезным: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8

?
Re: C# 8 - фича №1
От: samius Япония http://sams-tricks.blogspot.com
Дата: 03.12.19 07:57
Оценка: +1
Здравствуйте, Shmj, Вы писали:

S>Что из этого списка вы бы назвали наиболее важным и полезным: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8


PM
Re: C# 8 - фича №1
От: Ночной Смотрящий Россия  
Дата: 03.12.19 08:09
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Что из этого списка вы бы назвали наиболее важным и полезным: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8

S>?

switch expression, на втором месте ??=.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re: Using declarations, Null-coalescing assignment
От: Qbit86 Кипр
Дата: 03.12.19 08:10
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Что из этого списка вы бы назвали наиболее важным и полезным: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8


Using declarations, Null-coalescing assignment — но это скорее полезное, чем важное.
А то, что в списке важное, на мой взгляд, не так уж полезно.
Глаза у меня добрые, но рубашка — смирительная!
Re: C# 8 - фича №1
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 03.12.19 08:25
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Что из этого списка вы бы назвали наиболее важным и полезным: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8


S>?


Конечно ПМ, о чем так много говорили со времен немерля! И вот он почти в полной красе. Очень удобно.
Ну и Using declarations тоже для повседневности удобно.
Ну и Disposable ref structs и stackalloc тоже интересен особенно в будущем для объектов

https://xoofx.com/blog/2015/10/08/stackalloc-for-class-with-roslyn-and-coreclr/
и солнце б утром не вставало, когда бы не было меня
Re: C# 8 - фича №1
От: Kolesiki  
Дата: 03.12.19 10:14
Оценка: -6
Readonly members — можно сделать автоматом — человек тут не нужен.
Default interface methods — полное нарушение идеи контрактов, но если это полезно — почему бы и нет?
Pattern Matching — чахотошный, жалкое подобие оных из Nemerle.
Using declarations — давно пора, проснулись, эстонцы! Неужели кому-то было удобно писать тонны вложенных using'ов??
Static local functions — полезно, но чисто как помощь, чтобы не натупить внутри функции. В теории можно обойтись БЕЗ ключ.слова — чисто средствами среды.
Disposable ref structs — никогда не имел дела. Выглядит как костыль к некогда красивой схеме "язык C#".
Nullable reference types — полный идиотизм, костыль для макак, которые неспособны следить за собственным кодом.
Asynchronous streams — хайпофича. На деле асинхронных вещей в жизни не так много, чтобы СТОЛЬКО уделять им внимания.
Indices and ranges — слишком поздно и слишком криво. В языке D они были изначально и ВСЯ системная библиотека построена на них — потому и удобно писать программы, что ranges — не только в твоей либе, а вообще везде. А прикручивать их через 15 лет к устоявшейся .NET — глупо.
Null-coalescing assignment — после &= или += это как бы очевидная вещь, которая должна делаться _по_умолчанию_.
Unmanaged constructed types — игрища с unmanaged миром. Не интересно ни разу, должно отмереть как костыль.
Unmanaged constructed types — вообще не понял о чём. Кому-то хочется поиграть в стек?
Enhancement of interpolated verbatim strings — исправление собственных костылей

Итого, MS потратила сотни человекочасов на.... я даже не знаю, как это фуфло назвать. А ведь там всякие Всхлипперты сидят, надувают щёки и ходят за зарплатой. ЗА ЧТО??
Re: C# 8 - фича №1
От: Kolesiki  
Дата: 03.12.19 10:19
Оценка: -1
> You can retrieve the last word with the ^1 index:

За подобные вещи я б увольнял в тот же день — за этот идиотизм их проклянут навеки. Хотя... кого я хаю — банду индусни!
Re: C# 8 - фича №1
От: Mr.Delphist  
Дата: 03.12.19 10:43
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Что из этого списка вы бы назвали наиболее важным и полезным: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8


S>?


Всё важно. Язык постепенно вбирает в себя лучшие практики из того же C++ (const-методы), Swift (паттерн-матчинг и деконструкция), D (ranges) и т.п.

One language to rule them all... Да-а-а, моя прелессссть...
Re: C# 8 - фича №1
От: AlexRK  
Дата: 03.12.19 10:57
Оценка: +2 :)
Здравствуйте, Shmj, Вы писали:

S>Что из этого списка вы бы назвали наиболее важным и полезным: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8


S>?


Прочитал. Мда. Напоминает груду барахла, наваленного как попало, бессистемно и неконсистентно. Плюс для старого наследия ряд подпорок и костылей разной степени убожества.

В общем, повторяется история С++.

По теме — хрен знает, лично для себя из всего этого хлама самым полезным я бы назвал или новый using, или nullable ссылки.
Re[2]: C# 8 - фича №1
От: alexzzzz  
Дата: 03.12.19 11:06
Оценка: 1 (1) +1
Здравствуйте, Kolesiki, Вы писали:

>> You can retrieve the last word with the ^1 index:

K>За подобные вещи я б увольнял в тот же день — за этот идиотизм их проклянут навеки. Хотя... кого я хаю — банду индусни!

Выбрали самый естественный вариант. Это как дополнительный код для представления целых отрицательных чисел. Вроде можно было и попроще как-то, а на практике проще и удобнее именно так.

K>Readonly members — можно сделать автоматом — человек тут не нужен.


Нельзя автоматом — теряется половина смысла. Задача не только избавиться от защитного копирования структуры, но и чтобы программист случайным движением пальцев сам не заметив не вернул его обратно. Если ты написал readonly, а по факту метод куда-то что-то начал писать, то компилятор будет бить по рукам и ты сам осознанно решай, таки должен метод быть readonly или нет.
Отредактировано 03.12.2019 11:16 alexzzzz . Предыдущая версия . Еще …
Отредактировано 03.12.2019 11:06 alexzzzz . Предыдущая версия .
Re[2]: C# 8 - фича №1
От: Ночной Смотрящий Россия  
Дата: 03.12.19 11:56
Оценка:
Здравствуйте, Mr.Delphist, Вы писали:

MD>Swift (паттерн-матчинг и деконструкция)


При чем тут Свифт? Это все обсуждалось когда еще никакого свифта даже в проекте не было. Самим же идеям уже несколько десятилетий.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re: C# 8 - фича №1
От: alexzzzz  
Дата: 03.12.19 12:19
Оценка: +1
Здравствуйте, Shmj, Вы писали:

S>Что из этого списка вы бы назвали наиболее важным и полезным: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8


Важное и полезное — вещи субъективные. Объективно самое большое изменение — Nullable reference types, в силу масштабов проделанной работы и возможных последствий для экосистемы в целом.

Чем точно буду пользоваться:
— Using declarations — код опрятнее
— Static local functions — сначала не понимал смысла локальных функций, потом проникся; по сути большинство моих локальных функций — static
— Null-coalescing assignment — периодически хотелось, а теперь сможется
— Switch expressions — наверно треть моих switch — выражения
— Unmanaged constructed types — один раз точно очень хотелось, но не было возможности

Вероятно пригодятся:
— Stackalloc in nested expressions — сам stackalloc периодически использую
— Readonly members — знаю где применить, но пока неясно, насколько будет видна польза
— Enhancement of interpolated verbatim strings — убрали лишнюю путаницу

Хочется попробовать и посмотреть, что получится:
— Nullable reference types

Вещи утилитарные, не для широкого круга:
— Disposable ref structs
— Default interface methods — хотя объявлять static void Main() внутри интерфейса прикольно, класс для Main ничем не лучше

Скорее всего, пройдёт мимо меня, но может зацепить:
— Pattern matching enhancements: ... — из всего предыдущего пока зацепило только is type pattern expression.

Скорее всего, пройдёт мимо:
— Asynchronous streams

--
Из всех новых фич мне непонятна только одна: Indices and ranges. А именно, какую проблему пытались решить?
Отредактировано 03.12.2019 12:22 alexzzzz . Предыдущая версия .
Re[3]: C# 8 - фича №1
От: Mr.Delphist  
Дата: 03.12.19 13:17
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Здравствуйте, Mr.Delphist, Вы писали:


MD>>Swift (паттерн-матчинг и деконструкция)


НС> При чем тут Свифт? Это все обсуждалось когда еще никакого свифта даже в проекте не было. Самим же идеям уже несколько десятилетий.


Безусловно, все языковые идеи укладываются в две-три старых парадигмы времён мистера Беббиджа, ничего нового не родилось и не сможет (как невозможно возникновение внеземной жизни на Земле). Но паттерн-матчинг и деконструкция есть в таком куда более молодом языке как Swift (2014), а в таком старичке как C# (2000) — всё ещё в процессе прикручивания. Никакого иного скрытого смысла тут нет.
Re[3]: C# 8 - фича №1
От: Kolesiki  
Дата: 03.12.19 14:03
Оценка: +1
Здравствуйте, alexzzzz, Вы писали:

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


>>> You can retrieve the last word with the ^1 index:

K>>За подобные вещи я б увольнял в тот же день — за этот идиотизм их проклянут навеки. Хотя... кого я хаю — банду индусни!

A>Выбрали самый естественный вариант.


Самый тупой из всех возможных.
Индекс ПЕРВОГО элемента массива знают даже дети — 0. abc[0] — первый элемент. Сикарашка "^" нам говорит: а теперь мы считаем элементы с конца. И чтобы взять последний элемент... просто напиши abc[^0]! Это же логично!
Даже в плане употребления это намного правильнее. Никому не нужна "длина массива" — она неуклюжа как раз тем, что напрямую с массивом её нельзя использовать — её ВСЕГДА приходится вычитать. А понятие "индекс с конца" как раз и удобен тем, что видимый индекс и есть естественный индекс, как если бы мы считали от начала массива.

A>... а на практике проще и удобнее именно так.


Ровно наоборот — ваша неуклюжая практика как раз заставляет вычитать ненужную единицу из длины массива. Моя практика сразу пользуется естественным отсчётом.

K>>Readonly members — можно сделать автоматом — человек тут не нужен.


A>Нельзя автоматом — теряется половина смысла.


Тут согласен, но строго говоря, у меня вообще ни разу такого случая не было, чтобы "по ошибке" я лез переинициализировать целую структуру! Это довольно тупая ошибка и клянусь, если ЭТО для них проблема — вон из профессии! Это далеко не те вещи, о которых надо заботиться программисту.
Re[2]: C# 8 - фича №1
От: Kolesiki  
Дата: 03.12.19 14:12
Оценка:
Здравствуйте, alexzzzz, Вы писали:

A>Из всех новых фич мне непонятна только одна: Indices and ranges. А именно, какую проблему пытались решить?


Осмелюсь предположить, что MS-хипстота таки добралась до D и увидев, насколько мощно и логично выглядит "библиотека на диапазонах", обкакались от досады и непременно решили прикрутить во что бы то ни стало. Прикрутили. Как могли. С идиотским индексом конца "^1". Ну, кто ж убогого осудит! Сделали и сделали. Только позабыли, что на этих индексах построена ВСЯ библиотека Ди. В отличии от их новосклёпанного Core и тем более старичка Windows.FW; Вопрос: а смысл вообще?? "Шоб було?"
Получается, решили "проблему ущемлённого достоинства", только и всего.
Re: C# 8 - фича №1
От: sergeya Ниоткуда http://blogtani.ru
Дата: 03.12.19 14:24
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Что из этого списка вы бы назвали наиболее важным и полезным: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8


Pattern matching + Switch expressions. Очень не хватает после Nemerle.

Асинхронные потоки пока не распробовал, возможно буду использовать.

Остальное для меня не так актуально.
Мобильная версия сайта RSDN — http://rsdn.org/forum/rsdn/6938747
Автор: sergeya
Дата: 19.10.17
Re[4]: C# 8 - фича №1
От: Jack128  
Дата: 03.12.19 14:24
Оценка:
Здравствуйте, Kolesiki, Вы писали:

K>Самый тупой из всех возможных.

K>Индекс ПЕРВОГО элемента массива знают даже дети — 0. abc[0] — первый элемент. Сикарашка "^" нам говорит: а теперь мы считаем элементы с конца. И чтобы взять последний элемент... просто напиши abc[^0]! Это же логично!
Как часто ты будешь брать элементы по индексу и как часто ты будешь slice'ы до конца коллекции делать ?? ибо в твоем варианте, чтоб сделать копию коллекции нужно collection[0..^-1] писать, что вообще за гранью.
Re[4]: C# 8 - фича №1
От: alexzzzz  
Дата: 03.12.19 14:28
Оценка:
Здравствуйте, Kolesiki, Вы писали:

K>Индекс ПЕРВОГО элемента массива знают даже дети — 0. abc[0] — первый элемент. Сикарашка "^" нам говорит: а теперь мы считаем элементы с конца. И чтобы взять последний элемент... просто напиши abc[^0]! Это же логично!


Смотря, что ты считаешь концом массива. Логично, что последний элемент находится перед концом массива, а после или на конце ничего нет.
Re[4]: C# 8 - фича №1
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 03.12.19 14:30
Оценка:
Здравствуйте, Mr.Delphist, Вы писали:



MD>Безусловно, все языковые идеи укладываются в две-три старых парадигмы времён мистера Беббиджа, ничего нового не родилось и не сможет (как невозможно возникновение внеземной жизни на Земле). Но паттерн-матчинг и деконструкция есть в таком куда более молодом языке как Swift (2014), а в таком старичке как C# (2000) — всё ещё в процессе прикручивания. Никакого иного скрытого смысла тут нет.


Именно потому, что C# (2000) не так просто было и прикрутить ПМ. Тот же немерль и новый F# имеют ПМ изначальною
Тут на самом то деле нужны и Positional patterns и property pattern и как это совместить с уже существующем синтаксисе.
и солнце б утром не вставало, когда бы не было меня
Re[5]: C# 8 - фича №1
От: alexzzzz  
Дата: 03.12.19 14:30
Оценка:
Здравствуйте, Jack128, Вы писали:

J>Как часто ты будешь брать элементы по индексу и как часто ты будешь slice'ы до конца коллекции делать ?? ибо в твоем варианте, чтоб сделать копию коллекции нужно collection[0..^-1] писать, что вообще за гранью.


С диапазонами проще:
1) .. — весь диапазон
2) ..i — от начала до i не включая
3) i..j — от i до j не включая
4) j.. — от j до конца
Re[4]: C# 8 - фича №1
От: HrorH  
Дата: 03.12.19 14:32
Оценка: 8 (1) +1 :)
Здравствуйте, Kolesiki, Вы писали:

K>Самый тупой из всех возможных.

K>Индекс ПЕРВОГО элемента массива знают даже дети — 0. abc[0] — первый элемент. Сикарашка "^" нам говорит: а теперь мы считаем элементы с конца. И чтобы взять последний элемент... просто напиши abc[^0]! Это же логично!
K>Даже в плане употребления это намного правильнее. Никому не нужна "длина массива" — она неуклюжа как раз тем, что напрямую с массивом её нельзя использовать — её ВСЕГДА приходится вычитать. А понятие "индекс с конца" как раз и удобен тем, что видимый индекс и есть естественный индекс, как если бы мы считали от начала массива.


Why doesn't the new hat-operator index from the C# 8 array-slicing feature start at 0?
Объяснение не сильно понятное...Короче чтобы было удобнее код использующий машинное обучение переписывать с Питона на C#.
Re[4]: C# 8 - фича №1
От: Ночной Смотрящий Россия  
Дата: 03.12.19 14:49
Оценка:
Здравствуйте, Mr.Delphist, Вы писали:

MD>Безусловно, все языковые идеи укладываются в две-три старых парадигмы времён мистера Беббиджа


Нет.

MD>Но паттерн-матчинг и деконструкция есть в таком куда более молодом языке как Swift (2014)


Она много где есть. Сифт не обладает ни самой старой, ни самой сложной, ни самой похожей на шарп реализацией.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[5]: C# 8 - фича №1
От: AlexRK  
Дата: 03.12.19 15:54
Оценка:
Здравствуйте, alexzzzz, Вы писали:

A>Логично, что последний элемент находится перед концом массива, а после или на конце ничего нет.


Тогда настолько же "логично", что первый элемент находится после начала массива, а перед или в начале ничего нет.
Re[3]: C# 8 - фича №1
От: Sharov Россия  
Дата: 03.12.19 18:57
Оценка:
Здравствуйте, Kolesiki, Вы писали:


K>Осмелюсь предположить, что MS-хипстота таки добралась до D и увидев, насколько мощно и логично выглядит "библиотека на диапазонах",


Скорее до питона.
Кодом людям нужно помогать!
Re[6]: C# 8 - фича №1
От: alexzzzz  
Дата: 03.12.19 22:50
Оценка: -1
Здравствуйте, AlexRK, Вы писали:

A>>Логично, что последний элемент находится перед концом массива, а после или на конце ничего нет.

ARK>Тогда настолько же "логично", что первый элемент находится после начала массива, а перед или в начале ничего нет.

Перед началом массива действительно ничего нет, а как только он начался, идёт первый элемент. А как только кончился, снова ничего не идёт.



Кто-нибудь пишет такие циклы:
for (int i = 0; i <= array.Length - 1; i++)
?
Отредактировано 03.12.2019 23:04 alexzzzz . Предыдущая версия .
Re[4]: C# 8 - фича №1
От: alexzzzz  
Дата: 03.12.19 23:57
Оценка: +1
Здравствуйте, Kolesiki, Вы писали:

A>>Нельзя автоматом — теряется половина смысла.

K>Тут согласен, но строго говоря, у меня вообще ни разу такого случая не было, чтобы "по ошибке" я лез переинициализировать целую структуру! Это довольно тупая ошибка и клянусь, если ЭТО для них проблема — вон из профессии! Это далеко не те вещи, о которых надо заботиться программисту.

Необязательно переинициализировать целую структуру. У структуры может быть десяток полей, достаточно в методе пытаться изменить одно и он не сможет быть readonly-методом.
1) У больших структур больше накладных расходов на защитное копирование.
2) Именно у больших структур больше полей, которые тоже могут быть структурами с несколькими уровнями вложенности. В результате затруднительно держать в голове все поля всех структур и помнить, какой метод что и как делает.
3) Именно большие структуры труднее сделать целиком иммутабельными в соответствии с правилами хорошего тона. Но если нельзя всю её объявить readonly, можно дописать readonly её свойствам/методами по-максимуму и поручить следить за этим машине. Её для этого сделали, автоматизировать тупую работу.
Re[7]: C# 8 - фича №1
От: AlexRK  
Дата: 04.12.19 06:10
Оценка: +1
Здравствуйте, alexzzzz, Вы писали:

A>Image: ranges.png


У меня другая картинка:

---------------------------------------------
индекс от начала массива |   0  1  2  3  4
---------------------------------------------
элементы массива         |   a  b  c  d  e
---------------------------------------------
индекс от конца массива  |   4  3  2  1  0
---------------------------------------------


Разверни массив — и получишь индекс с конца. Как иначе-то?

Если иначе — то это не индекс с конца, а что-то другое. А если что-то другое, но при этом визуально похоже на индекс — то это тупизна и костыль, увеличивающий когнитивную нагрузку на ровном месте.
Re[5]: C# 8 - фича №1
От: Kolesiki  
Дата: 04.12.19 06:38
Оценка:
Здравствуйте, alexzzzz, Вы писали:

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


K>>Индекс ПЕРВОГО элемента массива знают даже дети — 0. abc[0] — первый элемент. Сикарашка "^" нам говорит: а теперь мы считаем элементы с конца. И чтобы взять последний элемент... просто напиши abc[^0]! Это же логично!


A>Смотря, что ты считаешь концом массива. Логично, что последний элемент находится перед концом массива, а после или на конце ничего нет.


Вы рассуждаете о массиве как о некоей линейной вещи, которая лежит в адресном пространстве (чисто сипиписное мышление — на примитивах CPU). Я же смотрю на массив ТОЛЬКО как на некий ряд элементов в пустоте. Что ВНЕ массива — мне не интересно. Соотв. у меня нет "нечто за гранью последнего элемента". Есть последний элемент. Он, как и первый элемент, легко индексируется сосвоего конца логичным индексом 0.
Re[7]: C# 8 - фича №1
От: Kolesiki  
Дата: 04.12.19 06:47
Оценка:
Здравствуйте, alexzzzz, Вы писали:

A>Кто-нибудь пишет такие циклы:

A>
for (int i = 0; i <= array.Length - 1; i++)
?


Ваша ошибка кроется в том, что ЛОГИЧЕСКИ вы работаете с "массивом наоборот" (т.е. говоря в коде "я ставлю ^ и значит мы работаем с конца"), а ФИЗИЧЕСКИ эта "крышечка" реализована как array.Length, что в корне неверно! Потому что тогда последний элемент массива должен быть не "^1" (как они нам пытаются всучить), а "^-1"!! Т.е. "взять длину и вычесть один для попадания на последний элемент". ВОТ ГДЕ бестолковое понимание целей послужило кривой реализации.
А всё от того, что они увидели в Ди знак $ (который в ДИАПАЗОНАХ означает именно длину), но попытались превратить его в "логический реверс".
Я ж грю — безалаберное стадо макак может месяцами рассуждать о фичах и всё равно выбрать самый тупой вариант — вот почему так редко пишу им issues — бесполезно, как об стенку горох.
Re[8]: C# 8 - фича №1
От: Kolesiki  
Дата: 04.12.19 06:52
Оценка: +1
Здравствуйте, AlexRK, Вы писали:

ARK>Если иначе — то это не индекс с конца, а что-то другое. А если что-то другое, но при этом визуально похоже на индекс — то это тупизна и костыль, увеличивающий когнитивную нагрузку на ровном месте.


Вот! Специально подчеркнул ключевой момент. Т.е. a[0] — это индекс. А a[^0] — хрен знает что, построенное на индусячей арифметике и длине массива. Лучше б они вообще не брались за "индексы с конца" — не такая это частая задача, чтобы пихать это в язык. Не говоря о том, что квалификация "пихунов" оставляет желать лучшего.
Re[6]: C# 8 - фича №1
От: alexzzzz  
Дата: 04.12.19 07:00
Оценка:
Здравствуйте, Kolesiki, Вы писали:

..1 — один элемент в начале
^1.. — один элемент в конце

..4 — четыре элемента
^4.. — четыре элемента

..n — n первых
^n..- n последних

..^2 — от начала до конца, кроме последних двух

Всё логично и просто.
Re[7]: 0..^0
От: Qbit86 Кипр
Дата: 04.12.19 07:19
Оценка:
Здравствуйте, alexzzzz, Вы писали:

A>..^2 — от начала до конца, кроме последних двух


А 0..^0 — просто от начала и до конца.

A>Всё логично и просто.


Да. [inclusiveStart, exclusiveEnd), всё, как Дейкстра завещал.
Глаза у меня добрые, но рубашка — смирительная!
Re[7]: C# 8 - фича №1
От: AlexRK  
Дата: 04.12.19 07:25
Оценка:
Здравствуйте, alexzzzz, Вы писали:

A>Всё логично


a[1] — второй элемент с начала
a[^1] — первый элемент с конца

a[^4] — последний элемент с конца
a[4] — oops, out of bounds exception, надо a[3]

A>и просто.


А причем тут индексы элементов?
Re[8]: C# 8 - фича №1
От: alexzzzz  
Дата: 04.12.19 12:28
Оценка: 1 (1)
Здравствуйте, AlexRK, Вы писали:

ARK>a[^4] — последний элемент с конца

ARK>a[4] — oops, out of bounds exception, надо a[3]

?

ARK>А причем тут индексы элементов?


Диапазон состоит из пары индексов, которые определяют его начало и конец. Он ими задаётся.
Re[9]: C# 8 - фича №1
От: AlexRK  
Дата: 04.12.19 12:40
Оценка:
Здравствуйте, alexzzzz, Вы писали:

ARK>>a[^4] — последний элемент с конца

ARK>>a[4] — oops, out of bounds exception, надо a[3]

A>?


Здесь что-то не так?

ARK>>А причем тут индексы элементов?

A>Диапазон состоит из пары индексов, которые определяют его начало и конец. Он ими задаётся.

Почему-то слово "индекс" меняет смысл при смене точки отсчета с начала массива на конец. Создается впечатление, что словом "индекс" называют две разные вещи.
Re[10]: C# 8 - фича №1
От: alexzzzz  
Дата: 04.12.19 14:23
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>>>a[^4] — последний элемент с конца

ARK>>>a[4] — oops, out of bounds exception, надо a[3]
A>>?
ARK>Здесь что-то не так?

Я не понял, что значит "последний элемент с конца" и как это связано с ^4.

ARK>Почему-то слово "индекс" меняет смысл при смене точки отсчета с начала массива на конец. Создается впечатление, что словом "индекс" называют две разные вещи.


Индекс был равнозначен смещению относительно начала. Когда говорим "смещение", надо уточнить, относительно чего. Когда говорим "индекс", подразумевается, что от начала. Начало массива совпадает с началом его первого элемента, смещение нулевое. У элемента с индексом N смещение N относительно начала массива.

Так было всегда. Сейчас добавилась возможность изменить точку отсчёта, а числовые индексы как были по сути смещениями, так и остались.


Жирные полосочки — это индексы/смещения.

У float с индексом 2 начало смещено на 2 относительно начала массива. Это смещение в "единицах float". Если умножить на 4, будет 8 — смещение в "единицах byte" или индекс первого байта из этого float.

Float с индексом 7 — последний. У него смещение 7 в "единицах float" относительно начала массива или 1 относительно конца. Если эту 1 умножить на 4, будет смещение 4 в "единицах byte" относительно конца. 7*4 -> 28 и ^1*4 -> ^4 указывают на один и тот же байт, начальный байт последнего float.

Kolesiki может по привычке искать начало последнего элемента через length-1, если нравятся отрицательные числа, но оператор ^ позволяет записать это короче: ^1. Крышечка — это не сам конец массива, это унарный оператор такой, возвращающий значение типа Index, привязанное к концу.

Раньше существовала путаница между "индексами" (которые считаются с нуля) и "порядковыми номерами" (первый, второй, ...). Говоришь "пятый элемент" и непонятно, это индекс или порядковый номер. Сейчас к этому добавятся ещё индексы типа ^5, которые индексы в смысле "значения типа Index". Если продолжать всё считать от начала, то ничего не изменится; а считать от конца непривычно никому, надо привыкнуть. Но когда модель мира в голове подтверждается наблюдениями, то это проще, чем когда они противоречат.
Re[11]: C# 8 - фича №1
От: AlexRK  
Дата: 04.12.19 16:07
Оценка:
Здравствуйте, alexzzzz, Вы писали:

ARK>>>>a[^4] — последний элемент с конца

ARK>>>>a[4] — oops, out of bounds exception, надо a[3]
A>>>?
ARK>>Здесь что-то не так?
A>Я не понял, что значит "последний элемент с конца" и как это связано с ^4.

Ну, то и значит. Последний элемент с конца это последний элемент, если вести отсчет с конца. Я не знаю, как иначе объяснить.

A>Индекс был равнозначен смещению относительно начала. Когда говорим "смещение", надо уточнить, относительно чего. Когда говорим "индекс", подразумевается, что от начала. Начало массива совпадает с началом его первого элемента, смещение нулевое. У элемента с индексом N смещение N относительно начала массива.


Что такое "начало" и "конец"? Если "начало" — это "адрес первого элемента", а конец — это "адрес последнего элемента", то конец массива — это "Length — 1", он совпадает с адресом последнего элемента и смещение относительно конца должно быть тоже нулевое.

A>Так было всегда. Сейчас добавилась возможность изменить точку отсчёта, а числовые индексы как были по сути смещениями, так и остались.


Но "смещение относительно конца" сделали неправильное.

A>У float с индексом 2 начало смещено на 2 относительно начала массива. Это смещение в "единицах float". Если умножить на 4, будет 8 — смещение в "единицах byte" или индекс первого байта из этого float.


ОК.

A>Float с индексом 7 — последний. У него смещение 7 в "единицах float" относительно начала массива или 1 относительно конца.


У него смещение в "единицах float" относительно конца должно быть 0, а не 1.

A>Если эту 1 умножить на 4, будет смещение 4 в "единицах byte" относительно конца. 7*4 -> 28 и ^1*4 -> ^4 указывают на один и тот же байт, начальный байт последнего float.


Что за странная арифметика? Чему равно ^1 и ^4? Почему ^4 = 28?

A>Kolesiki может по привычке искать начало последнего элемента через length-1, если нравятся отрицательные числа, но оператор ^ позволяет записать это короче: ^1. Крышечка — это не сам конец массива, это унарный оператор такой, возвращающий значение типа Index, привязанное к концу.


Только оператор ^ — это не индекс, а какая-то странная сущность.
Re[12]: C# 8 - фича №1
От: alexzzzz  
Дата: 04.12.19 18:38
Оценка: 1 (1)
Здравствуйте, AlexRK, Вы писали:

ARK>>>>>a[^4] — последний элемент с конца

ARK>>>>>a[4] — oops, out of bounds exception, надо a[3]
A>>>>?
ARK>>>Здесь что-то не так?
A>>Я не понял, что значит "последний элемент с конца" и как это связано с ^4.

ARK>Ну, то и значит. Последний элемент с конца это последний элемент, если вести отсчет с конца. Я не знаю, как иначе объяснить.


Последний элемент с конца — это первый элемент (если я правильно понимаю в слова). Если ^4 — первый элемент, значит от конца коллекции до её начала надо сделать 4 шага, значит в ней 4 элемента: 0, 1, 2 и 3.

ARK>Что такое "начало" и "конец"?


Если в чистом виде, то абстракция — на картинке выше нарисованы жирными линиями. Если в практическом плане, то да, скорее адрес. Как и «элемент» — абстрактная сущность, а на практике последовательность байт.

ARK>Если "начало" — это "адрес первого элемента", а конец — это "адрес последнего элемента",


В этом месте проблема.

Начало массива ― адрес первого байта массива, совпадает с адресом первого байта первого элемента. Тут трудностей не возникает.

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

Так обычно и принято задавать диапазоны: начало ― адрес/индекс/указатель на первый элемент, конец ― адрес/индекс/указатель на нечто после последнего элемента. Inclusive start, exclusive end.

Ну или второй популярный вариант: адрес/индекс/указатель на начало последовательности и количество элементов. Всю жизнь в NET API использовали второй вариант. Но по сути это одно и то же, переводится друг в друга одной арифметической операцией: start + length = end или end — start = length. Вот даже формулки простые и логичные.

ARK>Только оператор ^ — это не индекс, а какая-то странная сущность.



Обычный унарный оператор, только новый применительно к целым числам.
Отредактировано 04.12.2019 18:44 alexzzzz . Предыдущая версия . Еще …
Отредактировано 04.12.2019 18:42 alexzzzz . Предыдущая версия .
Отредактировано 04.12.2019 18:40 alexzzzz . Предыдущая версия .
Отредактировано 04.12.2019 18:39 alexzzzz . Предыдущая версия .
Отредактировано 04.12.2019 18:38 alexzzzz . Предыдущая версия .
Re[13]: C# 8 - фича №1
От: AlexRK  
Дата: 04.12.19 19:42
Оценка:
Здравствуйте, alexzzzz, Вы писали:

ARK>>Ну, то и значит. Последний элемент с конца это последний элемент, если вести отсчет с конца. Я не знаю, как иначе объяснить.

A>Последний элемент с конца — это первый элемент (если я правильно понимаю в слова). Если ^4 — первый элемент, значит от конца коллекции до её начала надо сделать 4 шага, значит в ней 4 элемента: 0, 1, 2 и 3.

Эту логику я не понимаю.

Почему нельзя сказать "если ^4 — первый элемент, значит, от конца коллекции до её начала надо сделать 5 шагов, значит, в ней 5 элементов: 0, 1, 2, 3 и 4"?
Почему нельзя сказать "если ^4 — первый элемент, значит, от конца коллекции до её начала надо сделать 4 шага, значит, в ней 4 элемента: 1, 2, 3 и 4"?

Вопросы риторические, конечно. Ответ "патамушта так сделали". Но консистентности за этим не видно. И, судя по всему, не только мне.

A>Конец же массива не может указывать на данные внутри массива.


Но ведь начало массива указывает на данные внутри массива, почему же конец не может?

A>Это не адрес последнего элемента, потому что тогда данные элемента могут лежать за концом массива — глупость получается.


Смотря как трактовать термин "конец массива". Массив — это абстракция.

A>Единственный рациональный вариант, который работает для однобайтовых и многобайтовых элементов, считать концом массива адрес первого байта за пределами последнего элемента массива. Как бонус, конец последнего элемента совпадает с концом всего массива.


Не вижу, чем этот вариант рациональнее варианта "считать концом массива адрес последнего элемента". Как бонус, индексы с конца начинаются с 0, а не с 1.

A>Так обычно и принято задавать диапазоны: начало ― адрес/индекс/указатель на первый элемент, конец ― адрес/индекс/указатель на нечто после последнего элемента. Inclusive start, exclusive end.


Вот в этой встроенной асимметричности как раз и корень проблемы.

A>Ну или второй популярный вариант: адрес/индекс/указатель на начало последовательности и количество элементов. Всю жизнь в NET API использовали второй вариант. Но по сути это одно и то же, переводится друг в друга одной арифметической операцией: start + length = end или end — start = length. Вот даже формулки простые и логичные.


Угу, только вот первый элемент a[0], а последний a[^1]. Просто и логично.
Re[14]: C# 8 - фича №1
От: samius Япония http://sams-tricks.blogspot.com
Дата: 04.12.19 21:23
Оценка:
Здравствуйте, AlexRK, Вы писали:

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


A>>Единственный рациональный вариант, который работает для однобайтовых и многобайтовых элементов, считать концом массива адрес первого байта за пределами последнего элемента массива. Как бонус, конец последнего элемента совпадает с концом всего массива.


ARK>Не вижу, чем этот вариант рациональнее варианта "считать концом массива адрес последнего элемента". Как бонус, индексы с конца начинаются с 0, а не с 1.


В соответствии с этим вариантом "считать концом массива адрес последнего элемента" выходит что последний элемент лежит за концом массива, т.е. массив не содержит последний элемент. И это ассиметрично с тем, что первый элемент (как и все, кроме последнего) все-таки лежит внутри массива, а не снаружи.
Re[14]: [startInclusive, endExclusive)
От: Qbit86 Кипр
Дата: 04.12.19 21:25
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Просто и логично. :)))


Соотношение «i + ^i = length» — без всяких ±1 — обусловлено соглашением, что диапазоны задаются полуоткрытыми, в виде [startInclusive, endExclusive):
int[] xs = array[0..array.Length]; // Весь диапазон.
int[] ys = array[0..^0]; // Тоже весь диапазон.
int[] zs = array[^array.Length..^0]; // Опять весь диапазон.
int[] ws = array[1..^1]; // Без крайних элементов.


Да, это просто и логично: https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html

А если наряду с ^ ввести унарный оператор ▽, который вычитает единицу, как вы предлагаете (то есть вместо «length − i» преобразуется в «length − i − 1»), то аналог пришлось бы записать так:
int[] xs = array[0..array.Length]; // Весь диапазон.
int[] ys = array[0..▽-1]; // WTF?
int[] zs = array[▽(array.Length-1)..▽-1]; // O_o.
int[] ws = array[1..▽0]; // ???
Глаза у меня добрые, но рубашка — смирительная!
Re[15]: C# 8 - фича №1
От: AlexRK  
Дата: 05.12.19 05:09
Оценка:
Здравствуйте, samius, Вы писали:

ARK>>Не вижу, чем этот вариант рациональнее варианта "считать концом массива адрес последнего элемента". Как бонус, индексы с конца начинаются с 0, а не с 1.


S>В соответствии с этим вариантом "считать концом массива адрес последнего элемента" выходит что последний элемент лежит за концом массива, т.е. массив не содержит последний элемент. И это ассиметрично с тем, что первый элемент (как и все, кроме последнего) все-таки лежит внутри массива, а не снаружи.


Ну, пусть так. Ничего плохого в этом не вижу, это же виртуальный конец.

Я не понимаю только, почему афтары, раз уж стибрили из D диапазоны, не сперли их в том же самом виде, а приделали свой велосипед с квадратными колесами (index-like сущность для обозначения конца диапазона).
Re[15]: [startInclusive, endExclusive)
От: AlexRK  
Дата: 05.12.19 05:18
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>Соотношение «i + ^i = length» — без всяких ±1 — обусловлено соглашением, что диапазоны задаются полуоткрытыми, в виде [startInclusive, endExclusive):


Я в курсе.

Q>int[] zs = array[^array.Length..^0]; // Опять весь диапазон.


Этот вариант не нужен.

Q>Да, это просто и логично: https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html


Это не абсолютная истина, а одно из мнений. Есть немало языков, в которых сделано иначе.

Q>А если наряду с ^ ввести унарный оператор ▽, который вычитает единицу, как вы предлагаете (то есть вместо «length − i» преобразуется в «length − i − 1»), то аналог пришлось бы записать так:


Надо было вот так:

int[] xs = array[0..array.Length]; // Весь диапазон.
int[] ys = array[0..$]; // Тоже весь диапазон.
int[] zs = array[^array.Length..^0]; // не нужно
int[] ws = array[1..$-1]; // Без крайних элементов.
Re[16]: C# 8 - фича №1
От: samius Япония http://sams-tricks.blogspot.com
Дата: 05.12.19 06:50
Оценка:
Здравствуйте, AlexRK, Вы писали:

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


ARK>>>Не вижу, чем этот вариант рациональнее варианта "считать концом массива адрес последнего элемента". Как бонус, индексы с конца начинаются с 0, а не с 1.


S>>В соответствии с этим вариантом "считать концом массива адрес последнего элемента" выходит что последний элемент лежит за концом массива, т.е. массив не содержит последний элемент. И это ассиметрично с тем, что первый элемент (как и все, кроме последнего) все-таки лежит внутри массива, а не снаружи.


ARK>Ну, пусть так. Ничего плохого в этом не вижу, это же виртуальный конец.

Даже для виртуального конца в случае с одноэлементным массивом не очень лаконично получается. Один и тот же элемент первый и последний в массиве. Как первый он лежит внутри массива, а как последний — вне массива. Ну и длина одноэлементного массива выходит что должна быть 0, т.к. граница начала совпадает с границей конца. Чушь какая-то.

ARK>Я не понимаю только, почему афтары, раз уж стибрили из D диапазоны, не сперли их в том же самом виде, а приделали свой велосипед с квадратными колесами (index-like сущность для обозначения конца диапазона).

Так, может быть, стибрили не из D?
Re[17]: C# 8 - фича №1
От: AlexRK  
Дата: 05.12.19 07:40
Оценка:
Здравствуйте, samius, Вы писали:

S>>>В соответствии с этим вариантом "считать концом массива адрес последнего элемента" выходит что последний элемент лежит за концом массива, т.е. массив не содержит последний элемент. И это ассиметрично с тем, что первый элемент (как и все, кроме последнего) все-таки лежит внутри массива, а не снаружи.

ARK>>Ну, пусть так. Ничего плохого в этом не вижу, это же виртуальный конец.

S>Даже для виртуального конца в случае с одноэлементным массивом не очень лаконично получается. Один и тот же элемент первый и последний в массиве. Как первый он лежит внутри массива, а как последний — вне массива.


Он не лежит вне массива, он лежит (начинается) в том месте, где стоит виртуальный маркер "последний элемент массива". Там, где стоит виртуальный маркер "последний элемент массива", массив не заканчивается.

S>Ну и длина одноэлементного массива выходит что должна быть 0, т.к. граница начала совпадает с границей конца.


Нет никакой "границы конца". Она не нужна. Есть индексы элементов. Индекс последнего элемента — это не конец массива.

Длина диапазона равна "индекс последнего элемента — индекс первого элемента + 1".

ARK>>Я не понимаю только, почему афтары, раз уж стибрили из D диапазоны, не сперли их в том же самом виде, а приделали свой велосипед с квадратными колесами (index-like сущность для обозначения конца диапазона).

S>Так, может быть, стибрили не из D?

Re[16]: [startInclusive, endExclusive)
От: Ночной Смотрящий Россия  
Дата: 05.12.19 07:44
Оценка:
Здравствуйте, AlexRK, Вы писали:

Q>>Да, это просто и логично: https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html

ARK>Это не абсолютная истина, а одно из мнений.

Офигительный аргумент. А у тебя, типа, абсолютная истина?
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[16]: [startInclusive, endExclusive)
От: Qbit86 Кипр
Дата: 05.12.19 07:48
Оценка:
Здравствуйте, AlexRK, Вы писали:

Q>>int[] zs = array[^array.Length..^0]; // Опять весь диапазон.

ARK>Этот вариант не нужен.

Это просто что-то вроде унарного и бинарного операторов:
System.Index operator ^(int value); // Index.FromEnd(value)
System.Range operator ..(Index start = 0, Index end = ^0); // new Range(start, end)


Говорить «этот вариант не нужен» — всё равно, что про обычный унарный минус сказать «мне -42 не нужно».

Q>>Да, это просто и логично: https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html


ARK>Это не абсолютная истина, а одно из мнений.


Ну да; эволюция лишь одно из мнений; а гравитация лишь теория.

ARK>Это не абсолютная истина, а одно из мнений.


В данном случае, это хорошо аргументированное мнение Эдсгера Дейкстры, лауреата премии Тьюринга, исполненное здравого смысла и практичности.

ARK>Есть немало языков, в которых сделано иначе.


Закрытые интервалы вместо полуоткрытых? Ну ок, могу только посочувствовать программистам на этих языках.

ARK>int[] ys = array[0..$]; // Тоже весь диапазон.


Это и так можно: int[] ys = array[0..];

Q>>int[] ws = array[1..^1]; // Без крайних элементов.


ARK>Надо было вот так:

ARK>int[] ws = array[1..$-1]; // Без крайних элементов.

Т.е. вместо символа «^» писать два символа «$-», в этом вся идея? И как оно будет согласовано с тем, что по-вашему крайний справа элемент должен иметь индекс $0?
var array = new[] { 2, 3, 5, 8 };
Index left = 1; // Index.FromStart(1);
Index right = ^1; // Index.FromEnd(1);
int[] xs = array[left..right]; // { 3, 5 }
int x = array[right]; // 8
Глаза у меня добрые, но рубашка — смирительная!
Re[17]: Абсолютная истина
От: Qbit86 Кипр
Дата: 05.12.19 08:00
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Офигительный аргумент. А у тебя, типа, абсолютная истина?


Даже если и не абсолютная; главное, не в одной компании с индусо-макаками типа ребят из Майкрософта, Эдсгера Дейкстры и Александра Степанова!</irony>
Глаза у меня добрые, но рубашка — смирительная!
Re[17]: [startInclusive, endExclusive)
От: AlexRK  
Дата: 05.12.19 08:08
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>Говорить «этот вариант не нужен» — всё равно, что про обычный унарный минус сказать «мне -42 не нужно».


ИМХО, это лишняя путаница. Это как представлять "42" как "--42".

ARK>>Есть немало языков, в которых сделано иначе.

Q>Закрытые интервалы вместо полуоткрытых? Ну ок, могу только посочувствовать программистам на этих языках.

Полагаю их потребность в сочувствии весьма маловероятной.

Q>Т.е. вместо символа «^» писать два символа «$-», в этом вся идея?


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

Q>И как оно будет согласовано с тем, что по-вашему крайний справа элемент должен иметь индекс $0?


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

Лично я бы предпочел что-то вроде такого (если не делать, как в D, а работать с индексами):

var array = new[] { 2, 3, 5, 8 };
Index left = 1; // Index.FromStart(1);
Index right = ^1; // Index.FromEnd(1);
int[] xs1 = array[left..right];     // [ ] - { 3, 5 }
int[] xs2 = array[left++..right];   // ( ] - { 5 }
int[] xs3 = array[left..right--];   // [ ) - { 3 }
int[] xs3 = array[left++..right--]; // ( ) - { }
int x = array[right]; // 5


Но вариант D еще лучше.
Re[18]: Непротиворечивость
От: Qbit86 Кипр
Дата: 05.12.19 09:07
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>ИМХО, это лишняя путаница. Это как представлять "42" как "--42".


И тем не менее, это не запрещено (с точностью до лексем «--» vs «- -»). Нет смысла это отдельно запрещать, усложняя язык.
Мне так вообще эти индексы не нужны сами по себе; но внутренняя непротиворечивость в целом важна.

ARK>Полагаю их потребность в сочувствии весьма маловероятной.


В этой двухстраничной статье вполне убедительно объясняется, почему манипуляции с полузакрытыми отрезками удобнее; а с закрытыми вызывают боль, страдание и ошибки ±1. Тут не обязательно даже на специальных языках программировать, достаточно просто поиспользовать API, разработанный без учёта этого соглашения.

ARK>Основная идея в том, что индекс как с начала, так и с конца записывается единообразно.


Это ведь перебор по исходной коллекции, не обращённой. Хочешь с нуля — реверсни коллекцию и считай с нуля по новой вьюшке. Это будет уже вопросом абстрактной итерации; а индексы в C# лежат на другом уровне абстракции. Просто шорткаты для арифметики.

ARK>Ну, очевидно, что с идеей захардкоженных полузакрытых диапазонов этот вариант не совместим.


Хорошо, что мы пришли к соглашению насчёт несовместимости. Поэтому текущая семантика ^ это не вопрос выбора — у разработчиков не было выбора сделать так или эдак. Поведение однозначно обусловлено тем, что объект типа Index может быть использован и для доступа к элементу последовательности, и для задания диапазона (в том числе для исключённой правой границы).
Глаза у меня добрые, но рубашка — смирительная!
Re: C# 8 - фича №1
От: varenikAA  
Дата: 05.12.19 09:57
Оценка: -1
Здравствуйте, Shmj, Вы писали:

S>Что из этого списка вы бы назвали наиболее важным и полезным: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8


S>?


Все это не нужно, т.к. есть nim/c(для совсем низкого уровня) и clojure для всего остального.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[18]: C# 8 - фича №1
От: samius Япония http://sams-tricks.blogspot.com
Дата: 05.12.19 09:59
Оценка:
Здравствуйте, AlexRK, Вы писали:

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


S>>Даже для виртуального конца в случае с одноэлементным массивом не очень лаконично получается. Один и тот же элемент первый и последний в массиве. Как первый он лежит внутри массива, а как последний — вне массива.


ARK>Он не лежит вне массива, он лежит (начинается) в том месте, где стоит виртуальный маркер "последний элемент массива". Там, где стоит виртуальный маркер "последний элемент массива", массив не заканчивается.


А где же будет виртуальный маркер "последний элемент массива" у пустого массива?
Re[19]: C# 8 - фича №1
От: AlexRK  
Дата: 05.12.19 10:31
Оценка:
Здравствуйте, samius, Вы писали:

ARK>>Он не лежит вне массива, он лежит (начинается) в том месте, где стоит виртуальный маркер "последний элемент массива". Там, где стоит виртуальный маркер "последний элемент массива", массив не заканчивается.


S>А где же будет виртуальный маркер "последний элемент массива" у пустого массива?


Там же, где и первого — то есть нигде. Для пустого массива маркеры первого и последнего элементов не определены.
Re[20]: C# 8 - фича №1
От: samius Япония http://sams-tricks.blogspot.com
Дата: 05.12.19 10:42
Оценка: 1 (1)
Здравствуйте, AlexRK, Вы писали:

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


ARK>>>Он не лежит вне массива, он лежит (начинается) в том месте, где стоит виртуальный маркер "последний элемент массива". Там, где стоит виртуальный маркер "последний элемент массива", массив не заканчивается.


S>>А где же будет виртуальный маркер "последний элемент массива" у пустого массива?


ARK>Там же, где и первого — то есть нигде. Для пустого массива маркеры первого и последнего элементов не определены.

Выходит, что по таким виртуальным маркерам нельзя определить размер массива, не будучи уверенным, что массив не пуст.
Re[19]: Непротиворечивость
От: AlexRK  
Дата: 05.12.19 10:55
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>В этой двухстраничной статье вполне убедительно объясняется, почему манипуляции с полузакрытыми отрезками удобнее; а с закрытыми вызывают боль, страдание и ошибки ±1.


Вся его "аргументация" заключается в словах "That is ugly". Очень убедительно.

Вот взять, скажем, вот это:

Consider now the subsequences starting at the smallest natural number: inclusion of the upper bound would then force the latter to be unnatural by the time the sequence has shrunk to the empty one.


Ему не нравится, что последовательность [2, 2] будет не пустой, а содержащей один элемент? Или я чего-то не понял? Лично для меня абсолютно очевидно, что элементы со второго по второй — это ровно один элемент, "2". Да и идея выражать пустой диапазон индексами довольно маразматична сама по себе, ИМХО.

Другой аргумент:

advantage that the difference between the bounds as mentioned equals the length of the subsequence


С одной стороны верно, с другой — в математике испокон веку длина диапазона равна (end — start + 1).
Re[21]: C# 8 - фича №1
От: AlexRK  
Дата: 05.12.19 10:57
Оценка:
Здравствуйте, samius, Вы писали:

S>>>А где же будет виртуальный маркер "последний элемент массива" у пустого массива?


ARK>>Там же, где и первого — то есть нигде. Для пустого массива маркеры первого и последнего элементов не определены.

S>Выходит, что по таким виртуальным маркерам нельзя определить размер массива, не будучи уверенным, что массив не пуст.

Да, нельзя. Точно так же, как нельзя взять первый элемент массива, не будучи уверенным, что массив не пуст.
Re[22]: C# 8 - фича №1
От: samius Япония http://sams-tricks.blogspot.com
Дата: 05.12.19 11:04
Оценка: 1 (1)
Здравствуйте, AlexRK, Вы писали:

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


S>>>>А где же будет виртуальный маркер "последний элемент массива" у пустого массива?


ARK>>>Там же, где и первого — то есть нигде. Для пустого массива маркеры первого и последнего элементов не определены.

S>>Выходит, что по таким виртуальным маркерам нельзя определить размер массива, не будучи уверенным, что массив не пуст.

ARK>Да, нельзя. Точно так же, как нельзя взять первый элемент массива, не будучи уверенным, что массив не пуст.

Взять-то понятно что нельзя. Но всегда можно было определить размер массива по его границам и это работает даже для пустых. Любого плюсиста стошнит от мысли о том, что begin() и end() для пустого массива не определены.
Re[23]: C# 8 - фича №1
От: AlexRK  
Дата: 05.12.19 11:09
Оценка:
Здравствуйте, samius, Вы писали:

S>>>Выходит, что по таким виртуальным маркерам нельзя определить размер массива, не будучи уверенным, что массив не пуст.

ARK>>Да, нельзя. Точно так же, как нельзя взять первый элемент массива, не будучи уверенным, что массив не пуст.
S>Взять-то понятно что нельзя. Но всегда можно было определить размер массива по его границам и это работает даже для пустых. Любого плюсиста стошнит от мысли о том, что begin() и end() для пустого массива не определены.

Не уверен, что качество абстракции определяется тем, тошнит от нее плюсистов или нет. Мало ли от чего их тошнит — кого-то от определения переменной как "a: T" вместо "T a", кого-то от отсутствия арифметики указателей, кого-то от замены "{ }" на "begin/end" или отступы. Если бы все на плюсистов ориентировались, большинства других языков бы не появилось.
Re[24]: C# 8 - фича №1
От: samius Япония http://sams-tricks.blogspot.com
Дата: 05.12.19 11:13
Оценка:
Здравствуйте, AlexRK, Вы писали:

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


S>>Взять-то понятно что нельзя. Но всегда можно было определить размер массива по его границам и это работает даже для пустых. Любого плюсиста стошнит от мысли о том, что begin() и end() для пустого массива не определены.


ARK>Не уверен, что качество абстракции определяется тем, тошнит от нее плюсистов или нет. Мало ли от чего их тошнит — кого-то от определения переменной как "a: T" вместо "T a", кого-то от отсутствия арифметики указателей, кого-то от замены "{ }" на "begin/end" или отступы. Если бы все на плюсистов ориентировались, большинства других языков бы не появилось.

Про плюсистов согласен. Не они определяют качество абстракции. Но совпадающие границы у пустого массива — вполне приличная абстракция. Лучше, чем другие варианты, как по мне.
Re[25]: C# 8 - фича №1
От: AlexRK  
Дата: 05.12.19 11:15
Оценка:
Здравствуйте, samius, Вы писали:

S>Но совпадающие границы у пустого массива — вполне приличная абстракция. Лучше, чем другие варианты, как по мне.


Ну а все же — почему лучше считать [2, 2] пустой последовательностью, чем последовательностью с одним элементом? В чем преимущество?
Re[26]: C# 8 - фича №1
От: samius Япония http://sams-tricks.blogspot.com
Дата: 05.12.19 11:25
Оценка:
Здравствуйте, AlexRK, Вы писали:

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


S>>Но совпадающие границы у пустого массива — вполне приличная абстракция. Лучше, чем другие варианты, как по мне.


ARK>Ну а все же — почему лучше считать [2, 2] пустой последовательностью, чем последовательностью с одним элементом? В чем преимущество?

Я тут вижу один элемент — двухэлементный кортеж.

printf "%A" [2,2] 
// [(2, 2)]
Re[27]: C# 8 - фича №1
От: AlexRK  
Дата: 05.12.19 11:29
Оценка:
Здравствуйте, samius, Вы писали:

S>>>Но совпадающие границы у пустого массива — вполне приличная абстракция. Лучше, чем другие варианты, как по мне.


ARK>>Ну а все же — почему лучше считать [2, 2] пустой последовательностью, чем последовательностью с одним элементом? В чем преимущество?

S>Я тут вижу один элемент — двухэлементный кортеж.

Хорошо. Почему лучше считать "2 .. 2" пустой последовательностью, чем последовательностью с одним элементом? В чем преимущество?
Re[28]: C# 8 - фича №1
От: samius Япония http://sams-tricks.blogspot.com
Дата: 05.12.19 11:35
Оценка:
Здравствуйте, AlexRK, Вы писали:

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


ARK>Хорошо. Почему лучше считать "2 .. 2" пустой последовательностью, чем последовательностью с одним элементом? В чем преимущество?


Тут все-таки зависит от контекста. Точнее, от ширины элемента. На числовой прямой у нас элементы (числа) не имеют ширины, поэтому [2..2] там вырожденный одноэлементный диапазон. Но когда у элемента есть ненулевая ширина, то по понятным причинам в диапазоне 2..2 не поместится ни одного элемента. Можно даже считать это [2.0 .. 2.0]
Re[29]: C# 8 - фича №1
От: AlexRK  
Дата: 05.12.19 11:53
Оценка:
Здравствуйте, samius, Вы писали:

ARK>>Хорошо. Почему лучше считать "2 .. 2" пустой последовательностью, чем последовательностью с одним элементом? В чем преимущество?


S>Тут все-таки зависит от контекста. Точнее, от ширины элемента. На числовой прямой у нас элементы (числа) не имеют ширины, поэтому [2..2] там вырожденный одноэлементный диапазон. Но когда у элемента есть ненулевая ширина, то по понятным причинам в диапазоне 2..2 не поместится ни одного элемента. Можно даже считать это [2.0 .. 2.0]


От ширины можно абстрагироваться, считать все элементы атомарными. Это вопрос абстракции. Можно с равным успехом принять 2..2 за диапазон длиной как 0 элементов, так и 1 элемент.

У Дейкстры я увидел два аргумента в пользу первого варианта:
1) можно получить длину без прибавления "1";
2) пустой диапазон представляется "уродливо".

Я нахожу оба этих аргумента несостоятельными — длину надо получать не жонглированием границ диапазонов, а функцией "length" (лучше и читабельность, и поддержка), а "уродлив", на мой взгляд, как раз-таки пустой диапазон в виде "2 .. 2" (опять же, для читабельности и поддержки пустой диапазон проверить можно и нужно соответствующей функцией).

Все это — тяжелое наследие жонглирования битами из С. Зачем на высоком уровне это нужно — пока понять не могу.
Re[20]: Пустая последовательность
От: Qbit86 Кипр
Дата: 05.12.19 12:40
Оценка:
Здравствуйте, AlexRK, Вы писали:

advantage that the difference between the bounds as mentioned equals the length of the subsequence


ARK>С одной стороны верно, с другой — в математике испокон веку длина диапазона равна (end — start + 1).


Так «в математике» и нумерация часто с единицы начинается. В математике не приходится много возиться с буферами. А в программировании приходится, и там принят подход (start, endExclusive) или (start, count), где endExclusive = start + count. Без ±1. Если это не дремучий Фортран или Паскаль. Полузакрытые интервалы удобно конкатенировать (приставлять рядышком), в них можно выразить пустую последовательность, они не подвержены «ошибкам на единицу».

Consider now the subsequences starting at the smallest natural number: inclusion of the upper bound would then force the latter to be unnatural by the time the sequence has shrunk to the empty one.


ARK>Да и идея выражать пустой диапазон индексами довольно маразматична сама по себе, ИМХО.


Нет, это очень изящная и практичная идея. Невозможность в закрытом интервале выразить пустую последовательность — это серьёзный недостаток.
Глаза у меня добрые, но рубашка — смирительная!
Re[21]: Пустая последовательность
От: AlexRK  
Дата: 05.12.19 13:15
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>В математике не приходится много возиться с буферами. А в программировании приходится, и там принят подход (start, endExclusive) или (start, count), где endExclusive = start + count.


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

Q>Полузакрытые интервалы удобно конкатенировать (приставлять рядышком)


А закрытые почему нельзя? range1.Concat(range2) или range1 + range2

Q>в них можно выразить пустую последовательность


range.IsEmpty()

Q>они не подвержены «ошибкам на единицу».


range.Length()

ARK>>Да и идея выражать пустой диапазон индексами довольно маразматична сама по себе, ИМХО.

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

Не вижу особого смысла в этой идее. Можно хотя бы иллюстративный пример задачи, которую она изящно и практично решает?
Re[22]: Примеры
От: Qbit86 Кипр
Дата: 05.12.19 13:48
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>range1.Concat(range2) или range1 + range2

ARK>range.IsEmpty()
ARK>range.Length()

Это всё вообще мимо кассы. Это внешний API. Как он устроен внутри? Как рейнджи создаются?

ARK>Можно хотя бы иллюстративный пример задачи, которую она изящно и практично решает?


Не, давай теперь ты примеры. На тех мифических языках, где в стандартных API рейнджи задаются закрытыми диапазонами. Начнём с D.
Глаза у меня добрые, но рубашка — смирительная!
Re[23]: End is not included
От: Qbit86 Кипр
Дата: 05.12.19 14:55
Оценка:
Q>Не, давай теперь ты примеры. На тех мифических языках, где в стандартных API рейнджи задаются закрытыми диапазонами. Начнём с D.

Ладно, я сам:
import std;

void main()
{
    foreach (int x; 2..6)
        writeln(x);

    foreach (int x; iota(2, 6))
        writeln(x);
}


Правая граница не выводится. Согласно документации:

Parameters:
B begin The starting value.
E end The value that serves as the stopping criterion. This value is not included in the range.
— https://dlang.org/phobos/std_range.html#iota

Глаза у меня добрые, но рубашка — смирительная!
Re[23]: Примеры
От: AlexRK  
Дата: 05.12.19 15:37
Оценка:
Здравствуйте, Qbit86, Вы писали:

ARK>>range1.Concat(range2) или range1 + range2

ARK>>range.IsEmpty()
ARK>>range.Length()
Q>Это всё вообще мимо кассы. Это внешний API. Как он устроен внутри? Как рейнджи создаются?

Это API рангов, обесценивающий рассуждения о нужности полуоткрытых диапазонов. Как он устроен внутри, не имеет значения — это деталь реализации. Создавать диапазон можно или как a..b, или через функцию а-ля CreateRange(a, b).

ARK>>Можно хотя бы иллюстративный пример задачи, которую она изящно и практично решает?

Q>Не, давай теперь ты примеры. На тех мифических языках, где в стандартных API рейнджи задаются закрытыми диапазонами. Начнём с D.

На D я уже приводил примеры выше, но у него не закрытые диапазоны.

Пример закрытого диапазона выглядит так же, как и пример полуоткрытого. Я просто пока не очень понял, в чем "изящество и практичность" полуоткрытых диапазонов. Если исключить низкоуровневое жонглирование битами, где оно может быть полезно, как и адресная арифметика.
Re[24]: End is not included
От: AlexRK  
Дата: 05.12.19 15:40
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>>Не, давай теперь ты примеры. На тех мифических языках, где в стандартных API рейнджи задаются закрытыми диапазонами. Начнём с D.

Q>Ладно, я сам:
Q>Правая граница не выводится. Согласно документации:

Я нигде не утверждал, что в D закрытые диапазоны. Там просто нет сбивающих с толку "индексов с конца". Это две разные вещи, хотя и смежные.
Re[24]: Примеры
От: Qbit86 Кипр
Дата: 05.12.19 15:59
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Это API рангов, обесценивающий рассуждения о нужности полуоткрытых диапазонов. Как он устроен внутри, не имеет значения — это деталь реализации.


Так а зачем тогда вообще притянули за уши сравнение с рангами в D? В C# сто лет уже такие ранги, называются IEnumerable<T>/Linq. Новые Index/Range — не про это.

ARK>Создавать диапазон можно или как a..b, или через функцию а-ля CreateRange(a, b).


И в обоих случаях правая граница не включается, правильно?

import std;

void main()
{
    foreach (int x; 2..6)
        writeln(x);

    foreach (int x; iota(2, 6))
        writeln(x);
}


Parameters:
B begin The starting value.
E end The value that serves as the stopping criterion. This value is not included in the range.
https://dlang.org/phobos/std_range.html#iota


ARK>Если исключить низкоуровневое жонглирование битами, где оно может быть полезно, как и адресная арифметика.


Вот мне недавно нужно было отформатировать кучу значений разных типов. И, чтобы не аллоцировать кучу строк, я форматировал всё в один общий массив char'ов. (В .NET Standard 2.1 для этого недавно появился API на Span'ах.) И размечен этот буфер аналогами ArraySegment, каждый внутри представлен парой (offset, count) с переходом в [start, end) при итерации.
И да, иногда некоторые значения — пустые строки, тогда их разметка — это пара (offset, 0) или [start, start) при итерации. Положение этого диапазона, хоть и пустого, в результирующем буфере не забывается, это тоже может использоваться.
Глаза у меня добрые, но рубашка — смирительная!
Re[30]: C# 8 - фича №1
От: samius Япония http://sams-tricks.blogspot.com
Дата: 05.12.19 16:20
Оценка:
Здравствуйте, AlexRK, Вы писали:

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


S>>Тут все-таки зависит от контекста. Точнее, от ширины элемента. На числовой прямой у нас элементы (числа) не имеют ширины, поэтому [2..2] там вырожденный одноэлементный диапазон. Но когда у элемента есть ненулевая ширина, то по понятным причинам в диапазоне 2..2 не поместится ни одного элемента. Можно даже считать это [2.0 .. 2.0]


ARK>От ширины можно абстрагироваться, считать все элементы атомарными. Это вопрос абстракции. Можно с равным успехом принять 2..2 за диапазон длиной как 0 элементов, так и 1 элемент.


Можно и сантиметры считать атомарными, с учетом того что расстояние между соседними всегда фиксированное. Но зачем?

ARK>Все это — тяжелое наследие жонглирования битами из С. Зачем на высоком уровне это нужно — пока понять не могу.

Затем, что жонглирование битами уже использовало старую абстракцию измерения, которая была задолго до битов. Затрудняюсь даже сказать, за сколько (тысячелетий).
Re[25]: Примеры
От: AlexRK  
Дата: 05.12.19 17:03
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>Так а зачем тогда вообще притянули за уши сравнение с рангами в D?


Мне нравится в D то, что нет индекса с конца — есть символ "$", обозначающий конец массива (просто сокращение от длины). И, как следствие, нет некрасивой асимметричности "первый элемент a[0], последний элемент a[^1]".

ARK>>Создавать диапазон можно или как a..b, или через функцию а-ля CreateRange(a, b).

Q>И в обоих случаях правая граница не включается, правильно?

Прикол в том, что, если использовать API Concat/Length/IsEmpty/etc., то разницы между включением и не-включением правой границы нет. Ну, во всяком случае, навскидку я ее не вижу.

Q>Вот мне недавно нужно было отформатировать кучу значений разных типов. И, чтобы не аллоцировать кучу строк, я форматировал всё в один общий массив char'ов. (В .NET Standard 2.1 для этого недавно появился API на Span'ах.) И размечен этот буфер аналогами ArraySegment, каждый внутри представлен парой (offset, count) с переходом в [start, end) при итерации.

Q>И да, иногда некоторые значения — пустые строки, тогда их разметка — это пара (offset, 0) или [start, start) при итерации. Положение этого диапазона, хоть и пустого, в результирующем буфере не забывается, это тоже может использоваться.

Если я правильно понимаю, особой пользы от "обратных индексов" в данном примере нет.

Про полуоткрытый диапазон — опять же, если я правильно понимаю, указатели на подстроки в буфере идут с разрывами? Если бы было без разрывов, то одно из полей явно лишнее, достаточно было бы одного смещения, разве нет? А если с разрывами, то start при переходе определяется не просто предыдущим "offset + count", а более сложной формулой. А раз так, не вижу особой беды туда сунуть дополнительно +1, чтобы работать с закрытым диапазоном. Лично для меня так было бы понятнее. Кстати, я не понял, а как же захватывается последний символ буфера, он будет в последнем элементе указывать ЗА массив?
Re[26]: Off-by-one error
От: Qbit86 Кипр
Дата: 05.12.19 22:22
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Если я правильно понимаю, особой пользы от "обратных индексов" в данном примере нет.


Пользы от обратных индексов мне нет никакой, я их не использую. Речь ведь не про их пользу для меня, а про их консистентность, раз уж такая фича есть. Так вот, определение ^i как length — i консистентно с соглашением о полуоткрытых интервалах, а другой вариант неконсистентен. А соглашение о полуоткрытых интервалах само по себе важно, и непосредственно связано с нумерацией от нуля и избеганием «ошибок на единицу». Поэтому такой подход и распространён в современных языках, придуманных после Фортрана.

Если они вам тоже не нужны, добавьте в EditorConfig строчки:
csharp_style_prefer_index_operator = false:suggestion
csharp_style_prefer_range_operator = false:suggestion


ARK>Про полуоткрытый диапазон — опять же, если я правильно понимаю, указатели на подстроки в буфере идут с разрывами?


В этом примере да, кроме отформатированных объектов был ещё посторонний текст.

ARK>Если бы было без разрывов, то одно из полей явно лишнее, достаточно было бы одного смещения, разве нет?


Всё так, такое тоже было в моей практике. Например, один сплошной массив всех ребёр графа (сгруппированных и упорядоченных по source-вершине), и дополнительная разметка, какой поддиапазон этого массива какой вершине инцидентен. Там без разрывов, и exclusiveEnd одного диапазона совпадает с inclusiveStart следующего, поэтому просто смещения. Всё прекрасно стэкается друг с другом, ±1 нигде не фигурируют, пустые диапазоны (отсутствуют исходящие рёбра в некоторых вершинах) вполне естественно сохраняются как повторяющиеся start'ы. Для порождения энумератора по поддиапазону как раз удобно представление [start, end), а не (offset, count) как принято в API, чтоб избежать лишних сложений.

ARK>А если с разрывами, то start при переходе определяется не просто предыдущим "offset + count", а более сложной формулой.


В этом случае start при переходе определяется своим сохранённым offset, а не рассчитывается от offset'а предыдущего.

ARK>А раз так, не вижу особой беды туда сунуть дополнительно +1, чтобы работать с закрытым диапазоном.


Так +1 или -1? Это просто не нужно, это лишнее пространство для ошибок, не говоря уже про лишние вычисления. И отсутствие единообразия: если без разрывов, то используем «полуоткрытый» подход, а если с разрывами, то «закрытый» подход.

ARK>Кстати, я не понял, а как же захватывается последний символ буфера, он будет в последнем элементе указывать ЗА массив?


Не вижу проблемы. Например, строка s = "key: 610" длиной 8 символов:
key: 610
     [  )
012345678


В ней подстрока 610 выкусывается диапазоном [5, 8), длина её 8 — 5 = 3 без ±1. Да, 8 здесь указывает на позицию вне массива, как и всегда в обращении array[length]. Проблем это не создаёт, потому что к элементу s[8] обращения нет, все индексы перебираются в асимметричных ограничениях 5 ≤ i < 8 без ±1.
Глаза у меня добрые, но рубашка — смирительная!
Re[8]: Ну тогда надо обшадить и всю скриптоту
От: Wolverrum Ниоткуда  
Дата: 06.12.19 01:35
Оценка: +1
Здравствуйте, Kolesiki, Вы писали: [-0]
Может вам и не очевидно, но народ в МС просто сделал по традиции всех (не могу даже вспомнить хоть один контрпример)
скриптовых ЯП

А в них, еще до рождения шипров, был стандарт: x[-1] — последний элемент списка/массива
Руби, Перл, "Наше автоматизация всё" Groovy(!), "наше ИИ всё" Python etc

А вы тут... развели категорическую бодягу.

Хотя нет, мир .NET упорно сопротивлялся этой весьма удобной фишке, в Powershell увы тоже нет.

Что не одобряю, так это испольвание уродской крыши вместо нормального, привычного отрицательного индекса
Отредактировано 06.12.2019 1:46 Wolverrum . Предыдущая версия .
Re[9]: Ну тогда надо обшадить и всю скриптоту
От: alexzzzz  
Дата: 06.12.19 07:29
Оценка:
W>Что не одобряю, так это испольвание уродской крыши вместо нормального, привычного отрицательного индекса

Проблема с минус нулём.

var start = 0;
var end = -0;
var slice = array[start..end];
Отредактировано 06.12.2019 8:37 alexzzzz . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.