Свойства языка программирования, облегчающие рефакторинг?

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

Я в основном думаю о функциях языка программирования, которые упрощают разработку инструментов статического анализа и рефакторинга (т.е. сравнивают Java и C ++, первый из которых лучше поддерживает рефакторинг).

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

Например, для Ada есть ASIS:

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

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

См. Также FAQ по ASIS.

Можете ли вы подумать о других языках программирования, которые предоставляют такой же всеобъемлющий и полный интерфейс для работы с исходным кодом специально для целей анализа / преобразования?

Я думаю о конкретных методах реализации для обеспечения ловушек низкого уровня, например о функциях основной библиотеки, которые предоставляют способ проверки AST или ASG во время выполнения.


person none    schedule 10.06.2009    source источник


Ответы (7)


Самым большим должна быть статическая типизация. Это позволяет инструментам гораздо лучше понимать, что делает код. Без этого рефакторинг становится во много раз сложнее.

person Bill K    schedule 10.06.2009
comment
Я действительно согласен, я думаю, что это одна из ключевых причин того, почему Ада настолько обширна из-за сильной поддержки Ады набора текста: en.wikibooks.org/wiki/Ada_Programming/Type_System - person none; 11.06.2009
comment
Рефакторинг на динамическом языке может быть большой проблемой, потому что вы никогда не знаете, какой будет переменная во время выполнения (скаляр, вектор, хэш, объект функции). - person none; 11.06.2009
comment
Если вы можете провести анализ потока, вы часто сможете определить, каков фактический тип динамической переменной; большинство хороших программистов не помещают 23 разных типа вещей в одну и ту же переменную. Таким образом, реальная потребность в поддержке рефакторинга динамических языков - это действительно хороший анализ потока. - person Ira Baxter; 16.06.2009
comment
@Ira Это очень интересно. Я боролся с рефакторингом в Ruby из-за динамической типизации. Люди говорят, что IDE не нуждаются в каких-либо дополнительных функциях, но мне бы хотелось, чтобы кто-нибудь построил такую ​​среду с анализом потоков, о котором вы говорите. - person LoveMeSomeCode; 12.08.2010
comment
@LoveMeSomeCode: см. Мой ответ на этот вопрос. Инструмент DMS имеет очень сильные механизмы анализа потока для C, Java, COBOL. Еще не настроен для Ruby: -} - person Ira Baxter; 12.08.2010

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

person Brian    schedule 14.06.2009

Верно, что конкретный язык программирования может облегчить анализ. Если вам нужны простые для анализа языки, выберите чисто функциональный.

Но на практике никто не программирует на чисто функциональных языках. (Ребята из Haskell будут подпрыгивать, когда увидят это, но серьезно, Haskell используется крайне редко).

Анализируемым язык программирования делает инфраструктура, предназначенная для поддержки анализа. ASIS Ады, приведенный выше, является отличным примером. Не смущайте тот факт, что ASIS был написан для Ada или написан на Ada; важно то, что кто-то серьезный хотел проанализировать Ada и вложил усилия в создание механизма анализа Ada.

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

В результате получился движок, который я считаю идеальным для анализа, рефакторинга, реинжиниринга и т.д.: наш DMS Software Engineering Toolkit. .

Он имеет общий синтаксический анализ, построение дерева, красивую печать, манипуляции с деревом, переписывание источника в источник, оценку грамматики атрибутов, управление и анализ потока данных. Он имеет качественный интерфейс для ряда широко используемых диалектов C и C ++, для Java, C #, COBOL и PHP, и даже для Verilog и VHDL (многие другие языки тоже, но не совсем того уровня).

Чтобы дать вам некоторое представление о его полезности, он использовался для преобразования кода JOVIAL для бомбардировщика B-2 в C ... без того, чтобы мы никогда не видели исходный код. См. http://www.semdesigns.com/Products/Services/NorthropGrummanB2.html

Итак, если у вас есть аналитическая инфраструктура, какие языковые функции могут помочь?

Статические типы помогают, ограничивая набор возможных значений, которые может принимать переменная, но только путем добавления ограниченного предиката с одним аргументом, например, «X - целое число». Я думаю, что больше помогает, так это утверждения в коде, потому что они захватывают предикаты с более чем одним аргументом, которые устанавливают отношения между переменными состояния, которые часто не могут быть обнаружены путем проверки кода (например, проблема или конкретная область информации, например, «X> Y + 3».) Инфраструктура анализа (и, откровенно говоря, программисты, читающие код) могут в идеале воспользоваться такими дополнительными фактами для обеспечения более эффективного анализа.

Такие утверждения обычно кодируются специальными ключевыми словами, такими как «assert», «pre (condition» и «post (condition)»), которые основаны на уважительной причине из литературы по доказательству теорем.

Но даже если у вас нет утверждений на вашем языке, их все равно легко закодировать: просто напишите оператор if с условием, содержащим отказ в утверждении, и тело будет делать что-то, что вызывает идиому, указывающую на невозможность, или нарушает семантику языка ( например, deref явно нулевой указатель), например "if (x> 0) fail ();"

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

person Ira Baxter    schedule 14.06.2009
comment
Мы не используем интерфейс EDG. EDG хочет быть компилятором, а это означает, что он ужасен для целей реинжиниринга. Наши инструменты предназначены для сбора всевозможной информации об исходном коде, отчасти для того, чтобы ее можно было восстановить позже. Это включает в себя такие действия, как сохранение комментариев с сохранением системы счисления целых чисел, НЕ расширение директив препроцессора там, где это возможно, анализ тысяч единиц компиляции за один прогон (компиляторы делают по одному) и т.д. чтобы убедиться, что мы можем правильно собрать все эти данные. - person Ira Baxter; 14.06.2009
comment
Я думаю, что сочетание а) функционального программирования (стиля), б) статической / строгой типизации, в) раскрытия внутренних компонентов языка (например, перехватов в парсер) и г) обеспечения инфраструктуры анализа и преобразования поверх него, в значительной степени является ответом. к исходному вопросу. - person none; 15.06.2009
comment
Подключается к парсеру a, не обязательно для компилятора языка; тот полностью настроен против того, чтобы помогать вам. Просто проще иметь парсер и механизмы анализа / преобразования, упакованные отдельно от языка и его компилятора. Но настоящая победа - это утверждения: никакое количество оборудования для анализа программ не может угадать свойства предметной области (в банках вы должны сэкономить деньги!), и поэтому они просто имеют чтобы вам сказали, какие инструменты у вас есть. Я хочу сказать, что их и так легко кодировать, но наша культура этого не поощряет. - person Ira Baxter; 05.07.2009

Отражение встроено в систему языка / типа. Это делает статический анализ и рефакторинг намного менее болезненными.

Это одна из причин того, почему инструменты Java и .NET настолько обычны и хороши. Это обеспечивает инструменты с гораздо большей функциональностью с точки зрения быстрого и надежного понимания зависимостей исходного кода, что помогает при статическом анализе исходного кода.

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

person Reed Copsey    schedule 10.06.2009
comment
Спасибо за ваш ответ - да, отражение, конечно, очевидный кандидат, тем не менее есть языки программирования, которые могут в значительной степени обходиться без него, т.е. Ada действительно не имеет большой поддержки для отражения, все же у нее действительно хороший интерфейс для источника анализ и преобразование кода. - person none; 10.06.2009
comment
Да - но вы упомянули ASIS в самом своем вопросе - Reflection, как концепция общего назначения, предоставляет многие из тех же преимуществ ASIS в другой форме. Вы можете выполнять анализ исходного кода только с исходным кодом (и без инструментов), но вы в основном пишете для этого свой собственный компилятор. - person Reed Copsey; 10.06.2009
comment
Возможно, я неправильно понимаю вопрос или этот ответ, но я думаю, что Reflection затрудняет рефакторинг. Информация, предоставленная для отражения, очень полезна, но фактические вызовы отражения внутри кода имеют тенденцию полностью уносить большинство инструментов из воды. Чтобы найти экземпляр класса, теперь вам нужно сканировать текстовые строки (нестабильные) или переключаться со статического анализа на анализ во время выполнения, что также является нестабильным, поскольку зависит от конкретного фрагмента кода. - person Bill K; 11.06.2009
comment
Рефлексия, реализованная в большинстве языков, не подходит для серьезного анализа кода. Обычно все, что вы получаете, - это возможность узнать о списках символов (например, методов), связанных с другим символом (например, классом). Чтобы провести серьезный анализ, вы хотите иметь возможность размышлять (действительно, спрашивать) о самой тонкой структуре / деталях любой детали программы. Для этого вам нужен прямой доступ к исходному тексту или его более легко управляемый эквивалент, например абстрактное синтаксическое дерево с таблицами символов, управлением и информацией о потоках данных. Это, в свою очередь, требует серьезной аналитической инфраструктуры. - person Ira Baxter; 14.06.2009
comment
Продолжая ... согласитесь с предыдущим комментарием, что рефлексия делает язык гораздо более сложным для рассуждений, потому что, если программа проводит анализ и хочет рассуждать о себе, теперь она также должна рассуждать о том, как она рассуждает о себе. Оттенки проблемы остановки сама по себе. Лучше IHMO иметь оборудование для анализа вне программы, чтобы этому анализатору не приходилось рассуждать и об анализаторе. - person Ira Baxter; 14.06.2009
comment
Я считаю эти аргументы довольно необоснованными. Отражение дает анализу еще один инструмент для работы - он ничего не отнимает. Инструмент может выполнять свою собственную полную компиляцию для построения полного синтаксического дерева и таблицы символов, но отражение упрощает это, поскольку ему больше не нужно понимать и компилировать библиотеки зависимостей и выполнять полную компиляцию, чтобы понять взаимосвязь с зависимые библиотеки. Я согласен с комментарием Билла К. - это может усложнить исходный код, но это зависит от того, как написан код (например: использование typeof (..) vs GetType (string) и т. Д.) - person Reed Copsey; 14.06.2009

Существует парадигма разделения языка «код - это данные». Например. каждая строка кода - это просто данные в терминах этого языка. Это делает рефакторинг таким же основным действием, как и простые операции с данными. И название этого языка - Лисп. ;)

Если серьезно, то «язык программирования» и «язык для машины» - это два разных требования. А идеальный язык для анализа может стать кошмаром для программиста. Более того, язык, предназначенный для некоторого анализа, может вообще не быть языком программирования. (На прошлой неделе я познакомился с языком для анализа указателей, и у него нет текстового представления и только два исполняемых оператора)

И еще: сначала нужно определить задачу, а затем ее решить. Например: если задача: «Я хочу писать безопасные программы, например, я хочу быть уверенным, что никогда не буду пытаться смешивать интегральные и символьные операнды», то вам нужен язык со статическими типами. Хорошо, «мне нужно знать во время выполнения, что я могу делать с внешними библиотеками» - отражение - ваш выбор. «Мне нужен универсальный язык программирования для обмена, преобразований и анализа» - скорее всего, это совсем не то, что вам нужно.

person vpolozov    schedule 14.06.2009

Для рефакторинга: самоподобие

Возможность принимать трансплантаты кода без навязчивого изменения или причудливой интерпретации. Примеры:

  • Извлеките фрагмент C ++ в новую процедуру, используя ссылочные параметры, чтобы предоставить ей доступ для изменения переменных.
  • Методы Python, Javascript и Lua - это просто функции с параметром self. *
  • В любом количестве языков функция, которая создает / заполняет структуру, может быть (более или менее тривиально) преобразована в конструктор.

Контрпримеры ...

  • Ruby (модули, классы), методы лямбда-блока и необработанные блоки: различия в семантике, мягко говоря, сбивают с толку. (это все, что я могу сказать наверняка.)

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

* Python почти похож на это. (Я забыл, в чем проблема. Возможно, что-то с этим связано, если метод был определен в классе или привит во время выполнения.)

person Anders Eurenius    schedule 14.06.2009

ИМО наиболее важным свойством является то, что язык полностью специфицирован и детерминирован. Например, в C поведение следующего кода не определяется спецификацией языка:

x++ = x++ + ++x;

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

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

person Erich Kitzmueller    schedule 15.06.2009