Какие функции языка программирования хорошо подходят для разработки живой среды программирования?
Я хотел бы построить "живую структуру кодирования".
Я должен объяснить, что подразумевается под "живой структурой кодирования". Я сделаю это, сравнивая кодирование в реальном времени с традиционным кодированием.
Вообще говоря, в традиционном программировании вы пишете код, иногда его компилируете, затем запускаете исполняемый файл или открываете скрипт в каком-то интерпретаторе. Если вы хотите изменить свое приложение, вы должны повторить этот процесс. Реальная среда кодирования позволяет обновлять код во время работы приложения и перезагружать его по требованию. Возможно, эта перезагрузка происходит каждый раз, когда файл, содержащий код, изменяется или каким-либо другим действием. Изменения в коде затем отражаются в приложении во время его работы. Нет необходимости закрывать программу, перекомпилировать и перезапускать ее.
В этом случае приложение является оконным приложением, которое имеет цикл обновления / рисования, скорее всего, использует OpenGL для графики, аудиобиблиотеку для обработки звука ( SuperCollider?) И, в идеале, сетевую библиотеку.
Конечно, я предпочел языки, хотя я не уверен, что какой-либо из них хорошо подойдет для такой архитектуры. В идеале я бы использовал Python, Lua, Ruby или другой язык более высокого уровня. Однако, недавно мой друг предложил Clojure как возможность, поэтому я тоже обдумываю это.
Я хотел бы знать не только, какие языки будут подходить для такого рода фреймворков, но, в общем, какие языковые особенности сделают такую фреймворк такой возможной.
8 ответов
В Clojure есть почти все, что вы, вероятно, захотите использовать в качестве живого языка программирования. Основные моменты:
- Интерактивный REPL - так что вы можете напрямую взаимодействовать с запущенной программой. Даже когда я занимаюсь "традиционным программированием", я обычно пишу код в интерактивном режиме и позже копирую нужные мне фрагменты в исходный файл. Clojure просто создан для такой работы - почти все в вашей программе проверяемо, модифицируемо и заменяемо во время выполнения.
- Отличная поддержка параллелизма - вы можете запускать параллельные фоновые задачи тривиально с помощью такого кода, как
(future (some-function))
, Что еще более важно, STM Clojure и акцент на высокопроизводительных неизменяемых структурах данных позаботятся о более тонких аспектах параллелизма (например, что произойдет, если я обновлю живую структуру данных, пока она находится в процессе рендеринга?) - Доступность библиотеки - это язык JVM, поэтому вы можете использовать все аудио, визуальные, IO или вычислительные инструменты, которые вам требуются в экосистеме Java. Их легко обернуть в одну или две строки Clojure, чтобы вы получили краткий интерфейс с нужными вам функциями.
- Макросы - поскольку Clojure является гомоиконическим языком, вы можете воспользоваться способностью Lisp писать мощные макросы, расширяющие язык. Вы можете эффективно создать точный синтаксис, который вы хотите использовать в реальной среде, и позволить компилятору выполнить всю тяжелую работу по созданию полного кода за кулисами.
- Динамическая типизация - о преимуществах этого можно утверждать обоими способами, но это, безусловно, огромное преимущество, когда вы пытаетесь писать код быстро и кратко.
- Активное сообщество с множеством интересных проектов - в сообществе Clojure вы, вероятно, найдете множество людей, заинтересованных в подобных методах живого кодирования.
Несколько ссылок, которые могут вас заинтересовать:
- Пол Грэхем на Лиспе - бить средние
- Пример кодирования Live Clojure с помощью синтезатора звука Overtone (интерфейс SuperCollider)
Я реализовал функцию живого кодирования в Lua как часть IDE ZeroBrane Studio. Он работает точно так же, как вы описали, перезагружая приложение после внесения изменений в код. Я работаю над возможными улучшениями, чтобы изменить значения во время выполнения, чтобы избежать полной перезагрузки приложения. Это чисто решение на основе Lua и не требует каких-либо изменений в виртуальной машине.
Вы можете увидеть демонстрацию живого кодирования, как это реализовано в настоящее время здесь: http://notebook.kulchenko.com/zerobrane/live-coding-in-lua-bret-victor-style.
С точки зрения используемых / необходимых языковых функций, я полагаюсь на:
- возможность прерывать / возобновлять работающее приложение (это основано на вызовах debug.hook и error()),
- возможность удаленного взаимодействия с (немодифицированным) приложением (это делается на основе debug.hook, поддержка взаимодействий TCP с select(), чтобы определить, отправляется ли новый запрос с хост-машины, а также на сопрограммы для переключения между основное приложение и модуль живого кодирования), и
- возможность внедрения нового кода в приложение (этот механизм также использует сопрограммы, но я уверен, что есть альтернативы). Существует также возможность добавить только модифицированный фрагмент, но он должен быть на уровне функции, и если эта функция является локальной для какой-либо другой функции, вам необходимо включить ее и так далее.
Единственное, что необходимо для этой работы, - это форма динамического связывания, например, передача сообщений в Erlang или eval
на многих других языках.
Если у вас есть динамическое связывание, то вы можете изменить цель сообщения, не затрагивая сообщение, или сообщение, не затрагивая цель - при условии, что цель определяется, когда вы пытаетесь отправить ей сообщение, и сообщение определяется для цели, на которые вы отправляете это, когда вы отправляете это.
При изменении цели все, что вам нужно сделать, это отправить сообщения предыдущей версии, пока новая версия не будет установлена, а затем выполнить небольшое заблокированное обновление для перехода к новой версии. Аналогично, при изменении сообщения вы просто обслуживаете старую версию, пока новая не станет доступной.
Однако готовый к использованию код с возможностью горячей замены все равно должен быть спроектирован как таковой - приложение должно быть достаточно модульным, чтобы замена реализации компонента не вызывала прерываний, и это может происходить только при тщательном программировании.
Хорошо и хорошо иметь "живое кодирование" на вашем устройстве разработчика, но способ прямого взаимодействия с развернутым сервером делает его намного ближе к "реальному". Для этого вам нужен REPL с поддержкой сети.
Clojure предоставляет это красиво в виде сокета Repl. Это позволяет вам удаленно подключаться к работающей версии вашего кода на вашем развернутом сервере Tomcat (например). Затем вы можете прикрепить ваш любимый инструмент разработки с поддержкой swank и взломать его.
Smalltalk, вероятно, лучший выбор для этого. В отличие от других, он имеет целую IDE для живого кодирования, а не просто REPL
Python на Google Appengine имеет repote_api_shell.py. это не полный набор live-кодирования - у clojure в emacs w/ swank-clojure было гораздо больше практического использования, поскольку интеграция "livecoding" в повседневные ритмы разработки - но многие люди не осознают, что это возможно в определенных средах Python.
$ PYTHONPATH=. remote_api_shell.py -s dustin-getz.appspot.com
App Engine remote_api shell
Python 2.7.1 (r271:86832, Jun 16 2011, 16:59:05)
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)]
The db, users, urlfetch, and memcache modules are imported.
dustin-getz> import models
dustin-getz> models.BlogPost(title='a modern take on automated testing', link='https://docs.google.com/document/pub?id=1DUxQogBg45rOTK4c5_SfEHiQcvL5c207Ivcy-gDNx2s', dont_publish_feed=False).put()
dustin-getz> items = models.BlogPost.all().filter('dont_publish_feed =', False).order('-published_date').fetch(100)
dustin-getz> len(items)
58
dustin-getz> for item in items[:5]: print item.title
a modern take on automated testing
Notes: Running a startup on haskell
the [un]necessity of superstar middle management in bigcos
"everything priced above its proper value"
stages of growth as a software engineer
Я работаю над возможностью написания кода для редактора PyDev's Python. Он был вдохновлен выступлением Брета Виктора " Изобретая принципы", и я реализовал отображение состояния программы, а также графику черепах. Они оба обновляются при вводе кода Python в Eclipse.
Проект размещен на GitHub, и я разместил демонстрационное видео, а также учебное пособие.
Основными функциями Python, которые я использовал, были абстрактные синтаксические деревья и динамическое выполнение кода. Я беру код пользователя, анализирую его в дереве, затем обрабатываю все операторы присваивания, итерации цикла и вызовы функций. Как только я проинструктировал дерево, я выполняю его и отображаю отчет или рисую запрошенную графику черепахи.
Я не реализовал функцию обмена, которую обсуждают другие ответы. Вместо этого я всегда запускаю код до завершения или по истечении времени ожидания. Я предполагаю, что живое программирование является улучшением разработки, основанной на тестировании, а не способом взлома живого приложения. Тем не менее, я буду больше думать о том, что даст мне возможность подменять части живого приложения.
У Tcl уже есть такая вещь. Например, вы можете написать программу с графическим интерфейсом, которая создает отдельное окно с интерактивной подсказкой. Оттуда вы можете перезагрузить свой код, ввести новый код и т. Д.
Вы можете сделать это с любым набором инструментов GUI, хотя некоторые будут намного сложнее, чем другие. С питоном все должно быть просто, хотя наличие отступов - ИМХО - усложняет интерактивное использование. Я вполне уверен, что большинство других динамических языков могут сделать это без особых проблем.
Посмотрите на это следующим образом: если ваш инструментарий позволяет открывать более одного окна, нет причины, по которой одно из этих окон не может быть интерактивной подсказкой. Все, что вам нужно, - это возможность открыть окно и какая-то команда "eval", которая запускает код, переданный ему в виде строки.