частичное проектирование по контракту с утверждениями

Хотелось бы получить мнения по поводу идеи частичного выполнения дизайна по контракту. Цель состоит в том, чтобы добавить к языкам, которые не предлагают ему облегченную версию контрактов (только инварианты и условия публикации), без необходимости во внешней библиотеке.

Мой пример написан на Java, но я полагаю, что идея хороша для многих объектно-ориентированных языков.

У нас есть такой класс:

class myClass{
    type1 field1;
    type2 field2;

    public myClass(type1 param1){
        //do something
    }

    public type3 method1(type1 param1, type3 param2){
        if (paramsAreNotOk()){
            throw new IllegalArgumentException();
        }
        // do a lot of things
        return //do something
    }
}

Мы расширяем приведенный выше код таким образом:

class myClass{
    type1 field1;
    type2 field2;

    public myClass(type1 param1){
        //do something

        assert invariant();
    }

    public type3 method1(final type1 param1, final type3 param2){
        assert invariant();
        myClass old;
        assert ((old = this.clone()) != null)

        if (paramsAreNotOk()){
            throw new IllegalArgumentException();
        }
        //do a lot of things
        type3 res = //do something

        assert method1_post(old, param1, param2, res);
        assert invariant();
        return res;
    }

    protected boolean invariant(){
        // states something about myClass and return a boolean
        // OR
        // uses some assertions on some helping methods
    }

    protected boolean method1_post(myClass old, type1 param1, type3 param2, type3 res){
        // states something about res and about the modifications made on old
        // OR
        // uses some assertions on some helping methods
    }
}

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

Теперь несколько вопросов:
- этот метод каким-либо образом вредит выступлениям? Я имею в виду, что даже локальные переменные old и res удаляются JIT-компилятором, если утверждения отключены?
- видите ли вы какие-либо недостатки этого подхода? Почему бы вам не использовать это в своих классах?
- вы можете предложить какие-нибудь улучшения?

Спасибо за чтение и за ваше мнение.


person heapOverflow    schedule 26.02.2011    source источник


Ответы (3)


Это не ужасно, и на самом деле об этом писали другие до вас. Например, см. Разработка программ на Java, который использует ваш подход к проверке инвариантов, но вызывает его repOK (), а не invariant ().

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

  • Допустим, у вас есть некий метод F, который вызывает другой метод G. Представьте, что F нарушает инвариант rep во время его выполнения, но исправляет вещи перед возвратом. Это разрешено, а в некоторых случаях требуется, но G этого не знает и неправильно вызовет исключение.
  • Конструкторы хуже. Скажем, класс D расширяет класс C и отменяет invariant (). D () вызывает C (), который вызывает D.invariant (), что неверно. C не обязательно должен удовлетворять инварианту D, который сильнее его собственного.
  • Если методу передаются неправильные аргументы клиентом вне класса, тогда IllegalArgumentException в порядке. Но если вызывающий находится внутри класса, это обычное нарушение старого контракта. Вы хотите провести различие между ними. Гэри Ливенс рассказывает о том, как JML делает это в этой статье, если тебе это интересно.
  • Постусловия, выраженные в терминах других методов класса (то есть «постусловия»), будут вызывать бесконечную взаимную рекурсию при проверке.

Я считаю, что DbC интересен, и если он есть в языке (или, что еще лучше, что-то вроде декораторов функций Python), или у вас есть такой инструмент, как Modern Jass, затем копайтесь. Но сделать это на чистой Java невозможно. Тем не менее, я работаю над инструментом проверки инварианта, который генерирует код, аналогичный тому, что у вас здесь, за исключением проблемы с цепочкой вызовов (вместо этого он расширяет классы для приема посетителя, который знает, когда следует выполнить проверку). Он требует Eclipse и имеет свои собственные проблемы (в основном связанные с плохими словами, такими как private и static), но механизм проверки - это чистая Java.

person johncip    schedule 23.10.2011

Если вам нужен «Дизайн по контракту» для Java, вы можете посмотреть, как (действительно) большие парни это делают! Вот недавний взгляд Google на тему «Контракты для Java»:

http://google-opensource.blogspot.com/2011/02/contracts-for-java.html

Теперь отвечу на два ваших вопроса:

- do you see any downside of this approach? Why wouldn't you use this in your classes?

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

- can you suggest any improvement?

Не изобретайте велосипед ...

person SyntaxT3rr0r    schedule 26.02.2011
comment
Я знаю, что есть несколько библиотек, пытающихся ввести контракты в java. Но здесь я просто хочу увидеть, как далеко может зайти программист, используя только базовые функции, предлагаемые языком. - person heapOverflow; 26.02.2011
comment
@heapOverflow: но аннотации являются основной функцией языка. Программист может пойти дальше, переписав основанный на аннотациях DbC на Java, используя только базовые функции языков (я имею в виду, что аннотации такие же базовые, как assert). - person SyntaxT3rr0r; 26.02.2011
comment
Проблемы со сторонней библиотекой заключаются в том, что вам нужно ввести код, который, возможно, не очень удобен для чтения, и что вам нужно изменить зависимости компиляции. Иногда это могло быть проблемой. Более того, что мне не нравится в конкретной библиотеке, которую вы связали, - это то, что ограничения хранятся в виде строк. У вас нет вариантов рефакторинга. - person heapOverflow; 26.02.2011

видите ли вы обратную сторону этого подхода? Почему бы вам не использовать это в своих классах?

Большинство Java-классов, которые я пишу, нельзя клонировать, потому что реализовать Clonable прямо в Java непросто. Поэтому я не применяю его, когда в этом нет крайней необходимости. Я бы не хотел делать это только из-за вашего подхода.

person Philipp Wendler    schedule 26.02.2011
comment
На мой взгляд, слабым местом этого подхода является необходимость использования метода клонирования с потерей читабельности. Но обратите внимание, что и то, и другое обусловлено пост-условиями, а не инвариантами. - person heapOverflow; 27.02.2011