Подтвердить что ты не робот

Как представить линейные типы в С#/. Net?

Есть ли разумный способ выразить концепцию линейного типа в .Net(Compact Framework/desktop 3.5 common subset), в таком способ: (a) требуемый синтаксис не становится чрезмерно многословным, запутанным или иным образом болезненным; и (б) инвариант может быть либо принудительно применен во время выполнения, либо проверен анализом кода во время компиляции (поэтому программист по обслуживанию во всем - спешить спешить не может просто беспечно игнорировать инвариант)? Идея здесь заключается в том, чтобы избежать необходимости защитного копирования объектов команд на границах подсистемы.

4b9b3361

Ответ 1

Существует два типа типов в .Net: типы ссылок и типы значений.

Когда вы копируете ссылочный тип, назначая его другой переменной, копируется только ссылка.

Когда вы копируете тип значения, копируется весь контент типа, байтом по байту.

В обоих случаях невозможно предотвратить, изменить или получить уведомление об этом (в отличие от конструкторов копирования С++). Это означает, что вы не можете реализовать линейные типы в .Net.

Вместо этого вы можете использовать неизменяемый (или зависающий) тип, как и другие.

Ответ 2

Линейные типы, основанные на теории линейной логики и тесно связанные с типами уникальности, являются типами, присваиваемыми значениям, имеющим свойство, что они имеют одну и только одну ссылку на них в любое время. Они полезны для описания больших неизменяемых значений, таких как файлы, строки и т.д.

Неизменяемым типом является тот, чье внутреннее состояние не может измениться после его создания.

A "глубоко неизменный тип" - это тот, чей график зависимости содержит ссылочные типы, которые также "глубоко неизменяемы". Если зависимые ссылочные типы сами по себе не являются "глубоко неизменными", тип называется "неглубоким неизменным".

В С# мы работаем со ссылочными типами и типами значений. Экземпляры ссылочных типов могут быть разделены между разрозненным одновременно исполняемым кодом, тогда как типы значений привязаны к стеку (если не помечены в бокс), скопированы при совместном использовании и, следовательно, автономны, хотя и не являются неизменяемыми (и могут содержать зависимости от других ссылочных типов, которые затем "копируются совместно" ).

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

В С# лучшее, что мы можем сделать, это описать наши намерения. Неизменяемость может быть частично реализована путем маркировки всех внутренних состояний типа как частных, так и только для чтения. Глубокая неизменность не может быть применена (и в этом случае не может быть мелкой), поэтому разработчик должен придерживаться намерений. Изменения состояния происходят через статические методы, которые возвращают новые экземпляры типа, содержащего запрашиваемое состояние.

public sealed class PersonImmutable {

    private readonly int _age;
    private readonly string _name;

    public PersonImmutable(int age, string name) { 
        this._age = age;
        this._name = name;
    }

    public int Age {
        get { return this._age; }
    }

    public string Name {
        get { return this._name; }
    }

    public static PersonImmutable NotifyBirthday(PersonImmutable source) {
        return new PersonImmutable(1 + source.Age, source.Name);
    }
}

Ответ 3

Предоставленная ссылка действительно определяет LinearVariable, которая может быть определена аналогично этому:

Option Explicit On
Option Strict On
Option Infer On 

<System.Diagnostics.DebuggerDisplay("{_state}: {_value}")> _
Class LinearVariable(Of T)
  Private Enum State
   Unassigned
   Assigned
   Used
 End Enum
 Private _state As State = State.Unassigned
 Private _value As T
 Public Sub New()
  'Allow creation and later assignment
 End Sub
 Public Sub New(ByVal Value As T)
  _value = Value
  _state = State.Assigned
 End Sub
 Public Shared Widening Operator CType(Value As T) As LinearVariable(Of T)
  Return New LinearVariable(Of T)(Value)
 End Operator
 Public Shared Widening Operator CType(Value As LinearVariable(Of T)) As T
  Return Value.Value
 End Operator
 Public Property Value As T
  Get
   If _state = State.Assigned Then
    _state = State.Used
#If DEBUG Then
    Return _value
#Else ' Release - free the reference immedately after use
    value = _value
    _value = Nothing
#End If
   End If
   If _state = State.Unassigned Then _
    Throw New NullReferenceException("LinearVariable is unassigned")
   If _state = State.Used Then _
    Throw New AccessViolationException("LinearVariable has already been accessed")
   Throw New InvalidOperationException
  End Get
  Set(ByVal Value As T)
   ' May want to check _state, although the "definition" at http://c2.com/cgi/wiki?LinearTypes seems to allow multiple writes
   _value = Value
   _state = State.Assigned
  End Set
 End Property
End Class

(Это было скомпилировано, но не проверено.)

Это, очевидно, работает только во время выполнения. Я не могу придумать какой-либо способ попытаться применить только одно использование .Value во время компиляции.

Обратите внимание, что вы можете сделать LinearVariable IDisposable, а затем поймать во время выполнения, когда его значение установлено и не используется.