Неизменяемые структуры данных в C # - PullRequest
9 голосов
/ 14 декабря 2011

Я читал некоторые записи в блоге Эрика Липперта о неизменных структурах данных , и я задумался, почему C # не встроил это в стандартные библиотеки? Кажется странным, что что-то с очевидным повторным использованием не было реализовано из коробки.

РЕДАКТИРОВАТЬ: Я чувствую, что, возможно, меня неправильно поняли по моему вопросу. Я не спрашиваю, как реализовать это в C #, я спрашиваю, почему некоторые из базовых структур данных (стек, очередь и т. Д.) Еще не доступны как неизменяемые варианты.

Ответы [ 6 ]

7 голосов
/ 24 декабря 2012

Сейчас.

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

3 голосов
/ 16 декабря 2011

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

В этом смысле «рынок» не обязательно относится к рыночной экономике, это так же верно, независимо от того, являются ли производители фреймворка / языка / оба коммерческими или некоммерчески ориентированные и распространяющие фреймворк / язык / оба (сейчас я просто скажу «фреймворк») по цене или бесплатно.В самом деле, проекты «бесплатно как в пиве и речи» могут быть в такой степени еще более зависимыми от своих рынков, чем коммерческие проекты, потому что их производители являются подмножеством их рынка.Рынок - это каждый, кто его использует.

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

Когда была разработана .NET, она была разработана для обслуживания будущего рынка.Поэтому идеи о том, что им послужит, повлияли на решения относительно того, что следует и не следует включать в FCL, среду выполнения и языки, с которыми он работает.

Кто-то решил, что нам, скорее всего, понадобится System.Collections.ArrayList.Кто-то решил, что нам, скорее всего, понадобится System.IO.DirectoryInfo, чтобы иметь метод Delete().Никто не решил, что нам, скорее всего, понадобится System.Collections.ImmutableStack.

Может быть, об этом вообще никто не подумал.Может быть, кто-то сделал и даже реализовал это, и тогда было решено, что оно не будет достаточно общего назначения.Может быть, это долго обсуждалось в Microsoft.Я никогда не работал на MS, поэтому понятия не имею.

Что я могу рассмотреть, так это вопрос о том, что люди, которые использовали .NET Framework в 2002 году, использовали в 2001 году.

Ну, COM, ActiveX, ("Classic") ASP и VB6 & VBScript теперь используются гораздо реже, чем раньше, поэтому можно сказать, что они были заменены на .NET.В самом деле, можно сказать, что это было намерение.

Как и VB6 & VBScript, значительное число тех, кто писал на C ++ и Java с Windows в качестве единственной или основной целевой платформы, теперь по крайней мере частично используют.NET вместо.Опять же, я думаю, что это можно назвать намерением, или, по крайней мере, я не думаю, что MS были удивлены, что все пошло именно так.

В COM у нас был метод foreach, основанный на объектах перечислителя, дляИтерация, которая имела прямую поддержку в некоторых языках (семейство VB *), и .NET у нас есть подход foreach к итерации, основанный на объектах перечислителя, который имеет прямую поддержку в некоторых языках (C #, VB.NET и другие) †.

В C ++ у нас был богатый набор типов коллекций из STL, а в .NET у нас есть богатый набор типов коллекций из FCL (и безопасных универсальных типов из .NET2.0 и далее).

В Java у нас был строгий стиль ООП "все для объекта" с небольшим набором методов, предоставляемых общим базовым типом, и механизмом бокса, позволяющим создавать простые эффективные примитивы при соблюдении этого стиля.В .NET у нас есть строгий стиль ООП «все для объекта» с небольшим набором методов, предоставляемых общим базовым типом и (другим) механизмом бокса, позволяющим создавать простые эффективные примитивы, сохраняя этот стиль.

Эти случаи демонстрируют выбор, который неудивителен, учитывая, кто, вероятно, в конечном итоге станет рынком для .NET (хотя такие широкие высказывания выше не следует воспринимать таким образом, чтобы недооценивать объем работы и тонкость проблем в рамкахкаждый из них).Другая вещь, которая относится к этому, - это когда .NET отличается от COM или классического VB, C ++ или Java, вполне может быть что-то вроде объяснения, приведенного в документации.Когда .NET отличается от Haskell или Lisp, никто не чувствует необходимости указывать на это!

Теперь, конечно, в .NET все сделано иначе, чем в любом из вышеперечисленного (или не было бы никакого смысла, и мы могли бы остаться с COM и т. Д.)

Однако, моя точка зрениячто из почти бесконечного диапазона возможных вещей, которые могут оказаться в такой среде, как .NET, есть некоторые полные легкие задачи («им может понадобиться какой-то тип строки ...»), некоторые близкие кочевидно («это действительно легко сделать в COM, поэтому это должно быть легко сделать в .NET»), некоторые сложные вызовы («это будет сложнее, чем в VB6, но преимущества того стоят»), некоторые улучшения(«Поддержка локали действительно может быть намного проще для разработчиков, поэтому давайте создадим новый подход к старой проблеме») и некоторые, которые были менее связаны с вышеупомянутым.

С другой стороны, мы можем, вероятно,все воображают что-то такое, что может быть странным («эй, все кодеры, как жизнь Конвея - давайте поместим жизнь Конвея прямо в рамки»), и, следовательно, нет ничего удивительного в том, что мы не можем его найти.upported.

До сих пор я быстро справился с тяжелой работой и сложными балансами дизайна таким образом, что дизайн, который они придумали, казался более простым, чем он, без сомнения, был.Скорее всего, чем более «очевидным» это кажется постороннему после свершившегося факта, тем сложнее это было для дизайнеров.

Неизменяемые типы коллекций попадают в большой диапазон возможных компонентов для FCL, которые, хотя и не такbizarre как идея встроенной поддержки conway, не так сильно требовалась, рассматривая рынок как изменяемый список или способ красиво инкапсулировать информацию о локали.Это было бы новшеством для большей части первоначального рынка, и, следовательно, риск того, что его не будут использовать.В альтернативной вселенной есть .NET1.0 с неизменяемыми коллекциями, но неудивительно, что здесь его нет.

* По крайней мере, для потребления.Создание IEnumVARIANT реализаций в VB6 было непростым и могло включать в себя запись значений указателей прямо в v-таблицы довольно неприятным способом, который внезапно приходит мне в голову, возможно, даже не допускается сегодняшним DEP.

† Иногда невозможно реализовать метод .Reset().Есть ли какая-то причина для этого, кроме как в IEnumVARIANT?Был ли он вообще когда-либо использован в IEnumVARIANT?

2 голосов
/ 14 декабря 2011

Я процитирую из этого Эрика Липперта блог , который вы читали:

потому что никто никогда не проектировал, не определял, не реализовывал, не тестировал, не документировал и не поставлял эту функцию.

Другими словами, нет другой причины, кроме того, что она не имела достаточно высокой ценности или приоритета, чтобы опередить все другие вещи, над которыми они работают.

2 голосов
/ 14 декабря 2011

Трудно работать с неизменяемыми структурами данных, если у вас нет функциональных программных конструкций.Предположим, вы хотите создать неизменный вектор, содержащий все остальные заглавные буквы.Как бы вы это сделали, если бы у вас

A) не было функций, которые выполняли такие вещи, как range(65, 91), filter(only even) и map(int -> char), чтобы создать последовательность в одном кадре и затем превратить ее в массив

B) создал вектор как изменяемый, добавил символы в цикл, а затем "заморозил" его, сделав его неизменным?

Кстати, C # имеет опцию Bв некоторой степени - ReadOnlyCollection может обернуть изменяемую коллекцию и не допустить ее мутации.Тем не менее, это задница в заднице делать это все время (и, очевидно, трудно поддерживать структуру разделения между копиями, когда вы не знаете, станет ли что-то неизменным или нет.) A - лучший вариант.

Помните, что когда существовал C # 1.0, у него не было анонимных функций, у него не было языковой поддержки для генераторов или другой лени, у него не было никаких функциональных API, таких как LINQ - даже карты или фильтра -- он не имел краткого синтаксиса инициализации массива (вы не могли написать new int[] { 1, 2, 5 }) и не имел универсальных типов;просто помещать вещи в коллекции и доставать их из коллекций, как правило, было больно.Поэтому я не думаю, что было бы отличным выбором потратить время на создание надежных неизменяемых коллекций с такой плохой языковой поддержкой для их использования.

2 голосов
/ 14 декабря 2011

Почему вы не можете создать неизменную структуру?Рассмотрим следующее:

public struct Coordinate
{
    public int X
    {
        get { return _x; }
    }
    private int _x;

    public int Y
    {
        get { return _y; }
    }
    private int _y;

    public Coordinate(int x, int y)
    {
        _x = x;
        _y = y;
    }
}

Это тип неизменяемого значения.

0 голосов
/ 15 декабря 2011

Было бы неплохо, если бы в .net была действительно надежная поддержка неизменяемых носителей данных (классов и структур).Одна из сложностей с добавлением действительно хорошей поддержки для таких вещей заключается в том, что использование максимальных преимуществ изменчивых и неизменных структур данных потребовало бы некоторых фундаментальных изменений в том, как работает наследование.Хотя я хотел бы видеть такую ​​поддержку в следующей основной объектно-ориентированной среде, я не знаю, может ли она быть эффективно использована в существующих средах, таких как .net или Java.

Чтобы увидеть проблему, представьте, чтоЕсть два основных типа данных: basicItem и deluxeItem (который является basicItem с несколькими добавленными дополнительными полями).Каждый может существовать в двух конкретных формах: изменяемый и неизменный.Каждый из них также может быть описан в абстрактной форме: читабельный.Таким образом, должно быть шесть типов данных;все, кроме ReadableBasicItem, должны заменять, по крайней мере, еще одного:

  1. ReadableBasicItem: Ничего не заменяемоеReadableDeluxeItem, MutableBasicItem (также ReadableBasicItem)
  2. ImmutableDeluxeItem: ReadableDeluxeItem, ImmutableBasicItem (также ReadableBasicItem)

Даже несмотря на то, что базовый тип данных имеет только одну базовую и один производный тип, у графа наследования есть два, так как у одного и того же графа наследования есть два, так как граф наследования имеет два, то у обоих есть два «наследственных» графа наследования, так как у одного и того же графа наследования есть два, так как у одного и того же «графа наследования» есть два », так как у одного и того же графа наследования есть два», то есть у обоих наследственный граф«MutableDeluxeItem» и «ImmutableDeluxeItem» имеют двух родителей (MutableBasicItem и ReadableDeluxeItem), оба из которых наследуются от ReadableBasicItem.Существующие классовые архитектуры не могут эффективно справиться с этим.Обратите внимание, что нет необходимости поддерживать обобщенное множественное наследование;просто для того, чтобы разрешить некоторые конкретные варианты, такие как описанные выше (которые, несмотря на наличие «алмазов» на графе наследования, имеют внутреннюю структуру, так что ReadableDeluxeItem и MutableBasicItem наследовали бы от «одного и того же» ReadableBasicItem).

Такжехотя поддержка такого стиля наследования изменяемых и неизменяемых типов может быть полезной, самой большой отдачи не было бы, если бы у системы не было средств, позволяющих отличить объекты, хранящиеся в куче, которые должны предоставлять семантику значений, от тех, которые должны представлять семантику ссылок,отличать изменяемые объекты от неизменяемых и может позволить объектам запускаться в «незафиксированном» состоянии (ни изменяемому, ни гарантированно неизменному).Копирование ссылки на объект кучи с семантикой изменяемых значений должно выполнять клонирование для каждого объекта для этого объекта и любых вложенных объектов с семантикой изменяемых значений, за исключением случаев, когда исходная ссылка будет гарантированно уничтожена;клоны должны начинать жизнь как незафиксированные, но должны быть CompareExchange'd для изменяемых или неизменяемых по мере необходимости.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...