
В.О. Сафонов
АРХИТЕКТУРЫ И МОДЕЛИ ПРОГРАММ И ЗНАНИЙ
Лабораторная работа номер 4.
Ознакомление с возможностями системы Spec# -
реализации расширения языка C# формальными спецификациями и
верификатором в стиле design-by-contract
Цель работы
Целью работы является ознакомление с системой Spec# - одной из первых в мире систем “доказательного программирования”, обеспечивающей разработку корректных программ, благодаря использованию формальных спецификаций и встроенного верификатора, проверяющего соответствие реализации программы ее спецификации.
Система Spec# разработана в Microsoft Research:
http://research.microsoft.com/en-us/projects/specsharp/
и реализована как расширение (add-in) к интегрированной среде Microsoft Visual Studio.
Теоретический материал по .NET и Visual Studio.NET представлен в лекциях 17 – 22 данного курса, материал по системе Spec# - в лекции 8 данного курса.
Программные инструменты, необходимые для лабораторной работы
- Операционная система Microsoft Windows XP, Windows 2003, Windows Vista, Windows 2008 или Windows 7.
- Microsoft Visual Studio.NET 2008.
-
Поиск и инсталляция системы Spec#
Скачайте дистрибутив (файл .msi) реализации Spec# для Visual Studio 2008 с сайта проекта:
http://research.microsoft.com/en-us/projects/specsharp/
Объем дистрибутива наиболее новой версии Spec# от ноября 2008 г. – около 6 Мбайт.
Инсталляция Spec# выполняется очень быстро, за 1-2 минуты.
В результате Вы получаете версию Visual Studip 2008, расширенную системой Spec#.
-
Запуск системы Spec# в составе Visual Studio 2008
Запустите Visual Studio 2008.
Выберите пункт основного меню: File / New / Projects. Убедитесь в том, что к типам проектов добавлен тип “Spec# projects”. Это означает, что система Spec# инсталлирована успешно (рис. 1).
В окне типов проектов визуализированы четыре примера программ на языке Spec#, инсталлируемые вместе с системой Spec#. Выберем проект Bag как наиболее простой (рис. 1).
Рис. 1. Выбор Spec# - проекта Bag для изучения
При открытии проекта в окне Visual Studio 2008 визуализируется исходный код на языке Spec# класса Bag, реализующего операции над множествами с повторяющимися элементами (по англоязычной терминологии – bags) – см. рис. 2.
Рис. 2. Открытие проекта Bags с исходным кодом класса Bag на языке Spec#
Приведем полный исходный код класса Bags на языке Spec#:
using System;
using Microsoft.Contracts;
public class Bag
{
int[]! elems; // Make this field [Rep]
int count; // Make this field [SpecPublic]!
invariant 0 <= count && count <= elems.Length;
public Bag(int[] initialElements) {
this.count = initialElements.Length; // Guard this dereference!
int[] e = new int[initialElements.Length]; // Make initialElements a non-null parameter!
initialElements.CopyTo(e, 0); // Use the less restrictive Copy method!
this.elems = e;
base();
}
public Bag(int[]! initialElements, int start, int howMany)
requires 0 <= start && 0 <= howMany;
requires start + howMany <= initialElements.Length;
{
this.count = howMany;
int[] e = new int[howMany];
Array.Copy(initialElements, start, e, 0, start+howMany); // Fix the fifth argument!
this.elems = e;
base();
}
public int RemoveMin() // Make this virtual
// Give this a precondition
{
// Expose the object
int m = System.Int32.MaxValue;
int mindex = 0;
for (int i = 0; i < count; i++) // Add a loop invariant!
{
if (elems[i] < m) {
mindex = i;
m = elems[i];
}
}
count--; // Make sure the object is exposed when you assign to its fields, potentially causing the object invariant not to hold!
elems[mindex] = elems[count]; // Add a precondition requiring at least one element in the bag!
return m;
}
public void Add(int x) // make this virtual
{
// Expose the object
if (count == elems.Length)
{
int[]! b = new int[2*elems.Length]; // Always grow the array, even if elems.Length == 0!
Array.Copy(elems, 0, b, 0, elems.Length);
elems = b;
}
elems[this.count] = x;
count++; // Make sure the object is exposed when you assign to its fields, potentially causing the object invariant not to hold!
}
}
Внимательно изучите данный код.
Как видно из комментариев и из анализа кода, он сознательно содержит ряд ошибок.
Основное отличие приведенного кода от кода на языке C# - наличие особых типов (non-null types), спецификаций пред- и постусловий и инвариантов.
Например, в классе Bag тип массива elems, представляющего множество с повторяющимися элементами, определен как int[]! , что означает “непустая ссылка на массив”. Если массив окажется пустым, будет зафиксирована динамическая ошибка.
В конструкторе класса Bag заданы предусловия (requires), требующие правильных соотношений между входными данными. Если эти соотношения будут нарушены, будет зафиксирована ошибка верификации, либо динамическая ошибка.
Для класса Bag специфицирован инвариант, требующий определенных соотношений между значениями полей. Если он будет нарушен, будет зафиксирована данамическая ошибка.
Таким образом, мы видим, что программирование на таком расширении C# обеспечивает бОльшую надежность программ, чем программирование на базовом языке C#:: введены дополнительные средства контроля корректности программ.
Однако это накладывает на программиста обязанность разработки пред- и постусловий и инвариантов, т.е. требует доказательного стиля программирования. К подобному стилю необходимо привыкнуть.