Моделирование аспектов статического контроля типов на утином типизированном языке

В моем текущем задании я создаю комплект сценариев Perl, которые зависят в большой степени от объектов. (использование Perl bless() на Хеше для получения максимально близко к OO)

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

Это приводит ко мне, откровенно говоря, не доверяя им код, написанный на утином типизированном языке. Как пример, я вижу слишком много проблем с ними, не получая явную ошибку для неправильного использования объектов. Например, если тип A имеет участника foo, и они делают что-то как, instance->goo, они не собираются видеть проблему сразу. Это возвратит пустое/неопределенное значение, и они, вероятно, потратят впустую час, находя причину. Затем закончите тем, что изменили что-то еще, потому что они правильно не определили исходную проблему.

Таким образом, я провожу мозговой штурм для способа сохранить мой язык сценариев (его быстрая разработка является преимуществом), но дайте явное сообщение об ошибке, когда объект не используется правильно. Я понимаю, что с тех пор нет этапа компиляции или статического контроля типов, ошибка должна будет быть во время выполнения. Все хорошо с этим, пока пользователь получает очень явное уведомление, говоря "этот объект, не имеет X"

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

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

8
задан Mike 29 May 2010 в 02:41
поделиться

3 ответа

Если у вас есть шанс добавить модули для использования, попробуйте Moose. Он предоставляет практически все возможности, которые вы хотели бы иметь в современной среде программирования, и даже больше. Он выполняет проверку типов, отлично наследуется, имеет возможности интроспекции, а с MooseX::Declare - один из самых приятных интерфейсов для классов Perl. Взгляните:

use MooseX::Declare;

class BankAccount {
    has 'balance' => ( isa => 'Num', is => 'rw', default => 0 );

    method deposit (Num $amount) {
        $self->balance( $self->balance + $amount );
    }

    method withdraw (Num $amount) {
        my $current_balance = $self->balance();
        ( $current_balance >= $amount )
            || confess "Account overdrawn";
        $self->balance( $current_balance - $amount );
    }
}

class CheckingAccount extends BankAccount {
    has 'overdraft_account' => ( isa => 'BankAccount', is => 'rw' );

    before withdraw (Num $amount) {
        my $overdraft_amount = $amount - $self->balance();
        if ( $self->overdraft_account && $overdraft_amount > 0 ) {
            $self->overdraft_account->withdraw($overdraft_amount);
            $self->deposit($overdraft_amount);
        }
    }
}

Я сам думаю, что это довольно круто. :) Это слой над объектной системой Perl, так что он работает с тем, что у вас уже есть (в основном).

С Moose вы можете легко создавать подтипы, так что вы можете быть уверены, что ваши данные действительны. Ленивые программисты согласны: так мало нужно сделать, чтобы подтипы работали в Moose, что проще сделать их, чем не делать! (из Cookbook 4)

subtype 'USState'
    => as Str
    => where {
           (    exists $STATES->{code2state}{ uc($_) }
             || exists $STATES->{state2code}{ uc($_) } );
       };

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

В Moose есть масса потрясающих вещей, подобных этой.

Поверьте мне. Проверьте это. :)

15
ответ дан 5 December 2019 в 07:10
поделиться

В Perl

  • требует, чтобы использовал строгие и предупреждения об использовании были включены в 100% кода

  • Вы можете попробуйте сделать почти частные переменные-члены, создав замыкания . Очень хороший пример - раздел «Частные переменные-члены, тип» в http://www.usenix.org/publications/login/1998-10/perl.html . Они не на 100% конфиденциальны, но довольно неочевидны, как получить доступ, если вы действительно не знаете, что делаете (и требуете, чтобы они прочитали ваш код и провели исследование, чтобы узнать, как).

  • Если вы не хотите использовать замыкания, следующий подход работает несколько хорошо:

    Сделайте все переменные-члены вашего объекта (также известные как хеш-ключи объекта в Perl) обернутыми в средства доступа. Есть способы сделать это эффективно, исходя из стандартов кодирования POV. Один из наименее безопасных - Class :: Accessor :: Fast. Я уверен, что у Moose есть способы получше, но я не так хорошо знаком с Moose.

    Убедитесь, что фактические переменные-члены «скрыты» в именах по частному соглашению, например $ object -> {'__ private__var1'} будет переменной-членом, а $ object-> var1 () будет средством доступа для получения / установки.

    ПРИМЕЧАНИЕ. И последнее, Class :: Accessor :: Fast - это плохо, поскольку его переменные-члены имеют общие имена с аксессорами. Но у вас могут быть очень простые компоновщики, которые работают так же, как Class :: Accessor :: Fast, и создают ключевые значения, такие как $ obj -> {'__ private__foo'} для «foo».

    Это не помешает им выстрелить себе в ногу, но БУДЕТ делать это намного сложнее.

    В вашем случае, если они используют $ obj-> goo или $ obj-> goo () , они БУДУТ получить ошибку времени выполнения, по крайней мере, в Perl.

    Они, конечно, могли бы изо всех сил сделать $ obj -> {'__ private__goo'} , но если они будут делать гонзо-ковбойское дерьмо из-за чистой лени, последнее - намного больше работы чем правильное выполнение $ obj-> foo () .

    Вы также можете сканировать кодовую базу, которая обнаруживает строки типа $ object -> {"_ , хотя, судя по вашему описанию, это может не сработать в качестве сдерживающего фактора.

4
ответ дан 5 December 2019 в 07:10
поделиться

Вы можете использовать Class::InsideOut или Object::InsideOut, которые обеспечивают настоящую конфиденциальность данных. Вместо того чтобы хранить данные в благословенной хэш-ссылке, благословенная скалярная ссылка используется как ключ к лексическим хэшам данных. Короче говоря, если ваши коллеги попробуют $obj->{member}, они получат ошибку времени выполнения. В $obj нет ничего, за что они могли бы ухватиться, и нет простого способа получить данные, кроме как через аксессоры.

Вот обсуждение техники inside-out и различных реализаций.

4
ответ дан 5 December 2019 в 07:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: