Чому "недійсний" не дозволений як загальний тип у C #


53

Які дизайнерські рішення стверджували на користь того, що їх voidне можна було сконструювати та не допустити як загальний тип? Зрештою, це просто спеціальний порожній structі уникнув би загального ПДФА, який мав чітких Funcта Actionделегатів.

(C ++ дозволяє явні voidповернення та дозволяє voidяк параметр шаблону)



2
@BenVoigt Це не обов'язково вимагає знань однієї людини, хоча тут є одна людина, яка може (легко, я вважаю) дати єдину правильну відповідь. Кожен, хто знайомий зі специфікацією, можливо, може відповісти на питання, особливо якщо він має знання мови програмування. Це також цікаве питання мовного дизайну / мовної реалізації, яке тут є тематичним.
Томас Оуенс

6
@BenVoigt: Чому ти так прагнеш, щоб без вагомих причин було закрито ідеально правильне та цікаве питання, що не задовольняє твою власну педантизм? У мене був пошук і відповіді не вдалося знайти; можливо, хтось тут прочитав повідомлення в блозі про це, можливо, люди, які прийняли рішення, хочуть відповісти на питання, можливо, хтось поспілкувався з людьми, які прийняли рішення про це, і самі задали питання, і вони можуть передати відповідь. Я зупинив публікації на цьому веб-сайті, і так багато, тому що люди здаються набагато більше зацікавленими у закритті питання, ніж у відповіді на запитання.

4
Я міг би вказати на "велику точку" питань і відповідей тут, особливо на SO, як правило, мають форму "що означає цей синтаксис?" Ці питання навряд чи закриваються, тому що кожен може складати і перераховувати визначення конституційних покажчиків для встановлення об'єктів. Більш цікаві запитання, які лежать поза пробитою доріжкою, виїжджають із сайту з певної педантичної причини: серйозно це десь кілька кілобайт десь у сховищі даних. Чи можемо ми всі просто розслабитися і прийняти навчання, а не нав'язувати довільно інтерпретовані правила, які служать дуже маленькій меті?

2
@ThomasOwens: Я в сенсі більше активний на цьому веб-сайті, ніж на SO. На цьому веб-сайті я розміщую відповідь приблизно на одне запитання на кожні 300. На ТАК я розміщую відповідь на приблизно одне запитання на кожні 1500. Різниця в активній чистій кількості відповідей пояснюється набагато більшою кількістю можливостей для відповідати на запитання C # на ТА.
Ерік Ліпперт

Відповіді:


69

Принципова проблема "пустоти" полягає в тому, що це не означає те саме, що і будь-який інший тип повернення. "void" означає "якщо цей метод повертається, то він взагалі не повертає значення". Не нульовий; null - значення. Він не повертає жодного значення.

Це дійсно заплутує систему типів. Система типу по суті є системою для здійснення логічних відрахувань щодо того, які операції є дійсними для певних значень; метод повернення недійсності не повертає значення, тому питання "які операції дійсні над цією річчю?" взагалі не має сенсу. Немає жодної "речі", щоб не було операції, дійсної чи недійсної.

Більше того, це псує час виконання щось жорстоке. Виконання .NET - це реалізація віртуальної системи виконання, яка задається як стек-машина. Тобто віртуальна машина, де всі операції характеризуються з точки зору їх впливу на стек оцінки. (Звичайно, на практиці машина буде реалізована на машині як з стеком, так і з регістрами, але система віртуальної роботи передбачає лише стек.) Ефект виклику недійсного методу принципововідрізняється від ефекту виклику недійсного методу; недійсний метод завжди ставить щось на стек, що може знадобитися вискочити. Недійсний метод ніколи не ставить щось на стек. Отже, компілятор не може ставитись до недійсних та недійсних методів однаково у випадку, коли повернене значення методу ігнорується; якщо метод недійсний, то значення повернення немає, тому поп не повинен бути.

З усіх цих причин "недійсність" не є типом, який може бути ініційований; у неї немає значень , у цьому вся суть. Це не конвертоване в об'єкт, і метод повернення порожнеч ніколи не може бути поліморфно оброблений методом, який не повертає недійсність, тому що це пошкоджує стек!

Таким чином, void не може використовуватися як аргумент типу, що шкода, як ви зазначаєте. Було б дуже зручно.

З користю заднього огляду, всім зацікавленим було б краще, якби замість нічого іншого, метод, що повертає недійсність, автоматично повертав "Одиницю", магічний одинарний посилання типу. Тоді ви б знали, що кожен виклик методу ставить щось на стек , ви знаєте, що кожен виклик методу повертає щось, що може бути призначено змінній типу об'єкта , і, звичайно, Unit може використовуватися як аргумент типу , так що не потрібно мати окремих типів делегування Action та Func. На жаль, ми не в світі.

Щоб дізнатися більше про цю думку, див:


C ++ підтримує його без використання магічного однотонного типу. Але я припускаю, що це стосується C ++, використовуючи зовсім інший стиль "generics", а потім C #.
Вінстон Еверт

4
@WinstonEwert - Я впевнений, що C ++ взагалі не підтримує дженерики, але має шаблони, які принципово відрізняються. Як я розумію, компілятор за допомогою шаблонів здійснює глобальний пошук і замінює параметри вашого типу, але за допомогою дженерики система типів створює належний тип. Я також вважаю, що тому помилки шаблону C ++ були настільки чіткими. Я впевнений, що Ерік мене виправить, якщо я сказав щось не зовсім правильно
Адам Ракіс

1
Я думаю, що всі структури обробляються під час компіляції, щоб отримати правильне розміщення на стеці та в інших місцях, де вони вписані. Таким чином, Voidповинно бути нормально, щоб передаватись як нескінченна кількість аргументів всередині 0 байт стека. Коли будь-яка структура потребує перетворення на objectметод або виклик методу (для отримання this), він встановлюється в купі з розміщенням на купі з Typeпосиланням, вставленим перед областю полів пам'яті (для багатьох реалізацій CLR), і таким чином можна обробляти належним чином. Щодо мене тип - це просто групування об’єктів, які можна виділити за деякими характеристиками (полями). Voidє лише одним об’єктом.
они

1
@ OlivierJacot-Descombes: Якби voidтип порожнього значення був, то це твердження було б переведеним на нульові інструкції машинного коду. Не дуже корисний для жорстко закодованого типу Void, але корисний у випадках, коли тип має декілька загальних параметрів, але деякі не потрібні в певних випадках.
supercat

2
@EricLippert: Для правильного поводження зі значеннями повернення значень типу знадобиться можливість виводити змінну кількість слів із стека. Чи будуть якісь принципові труднощі з дозволом кількості слів дорівнювати нулю? Якщо абонент відповідає за розподіл простору та передачу byref, система типів повинна визнати, що пустий byref не має жодного значення, і, можливо, це не вважалося вартим зусиль, але я не бачу жодної "фундаментальної" проблеми .
supercat

9

Від: http://connect.microsoft.com/VisualStudio/feedback/details/94226/allow-void-to-be-parameter-of-generic-class-if-not-in-c-then-just-in- час виконання

Це насправді задумом - ми не допускаємо жодного примірника типу void (разом з багатьма іншими типами під час виконання). Ви також не можете створити ніколи недійсні чи недійсні []. Ми підключили ці отвори для безпеки.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.