GoSuda

Сравнение языковых дизайнов в среде генерации кода с помощью LLM: стоимость абстракции и явность Go

By Rabbit Princess views ...

Современные языки

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

1. Объектно-ориентированное проектирование ( OOP )

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

2. Синтаксический сахар и выражения

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

3. Система модулей

Современные языки позволяют разделять программу на несколько единиц и управлять ими посредством системы модулей. Это облегчает повторное использование кода и управление зависимостями, а также упрощает сопровождение даже при значительном росте масштаба проекта. Типичными примерами являются Maven/Gradle для Java, Cargo для Rust и npm/yarn для TypeScript.

4. Промежуточный язык и виртуальные машины

Современные языки для обеспечения независимости от платформы, оптимизации производительности и безопасности используют промежуточный язык и виртуальные машины. Типичными примерами являются JVM, LLVM, WASM, GraalVM и др.

Разработка в эпоху ИИ и ограничения современных языков

Современные языки возникли из предпосылки, что большую часть кода пишет человек. Естественно, целью современных языков является сокращение повторяющейся работы, повышение производительности и создание структур, позволяющих разработчикам эффективно взаимодействовать при реализации крупного программного обеспечения. Однако в эпоху ИИ эта предпосылка постепенно теряет силу. Инструменты на основе ИИ, такие как Copilot, Cody и др., автоматизируют значительную часть написания кода, и объем кода, который может создать один разработчик, стремительно возрастает. В результате особенности современных языков, которые раньше воспринимались как преимущества, постепенно превращаются в недостатки устаревшего подхода.

Объектно-ориентированное проектирование

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

 1public class AnimalHandler {
 2    public void handle(Animal animal) {
 3        animal.speak();
 4    }
 5}
 6
 7public class Main {
 8    public static void main(String[] args) {
 9        AnimalHandler handler = new AnimalHandler();
10
11        Animal a1 = new Dog();
12        Animal a2 = new Cat();
13        Animal a3 = new Horse();
14
15        handler.handle(a1);
16        handler.handle(a2);
17        handler.handle(a3);
18    }
19}

В приведенном коде, чтобы определить, какое действие фактически выполняет метод speak(), ИИ должен повторять следующие выводы:

  1. Экземпляром какого конкретного класса является animal?
  2. Где определен переопределенный в этом классе метод speak()?
  3. Где находятся определения классов Dog и Cat и какое поведение они содержат внутри?
  4. Не существует ли возможности того, что классы Dog и Cat будут переопределены в других классах?

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

Синтаксический сахар и выражения

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

Промежуточный язык и виртуальная машина

ИИ в основном обучается на исходном коде. Напротив, промежуточный язык (байткод) в процессе компиляции лишается смысловой информации, такой как имена переменных, и виртуальная машина должна переинтерпретировать его во время выполнения. Для ИИ понимание или преобразование такого кода является крайне сложной задачей. Например, для ИИ возможно преобразование TypeScript в Go, но преобразование байткода движка V8 в байткод JVM или в машинный код практически невозможно.

Настоящие современные языки в эпоху ИИ

Из изложенного выше следует, что особенности современных языков на самом деле являются устаревшими элементами, не подходящими для эпохи ИИ. Так какой же язык может стать наиболее подходящим современным языком для эпохи ИИ? Ответ можно найти в элементах, которые прежние современные языки отвергали. Современный язык эпохи ИИ должен:

  1. Обладать явным синтаксисом и естественным потоком выполнения.
  2. Отказаться от избыточного ООП и иметь плоскую, простую структуру.
  3. Вместо необязательного синтаксического сахара и неявных шаблонов использовать ограниченный набор базовых ключевых слов для реализации множества возможностей.
  4. Иметь простую и предсказуемую систему сборки, а не сложную.

Language, наиболее полно соответствующим этим критериям, является Golang. Язык Go спроектирован так, чтобы практически любые необходимые функции можно было реализовать на основе минимального набора ключевых слов и простой комбинации синтаксических конструкций, и он последовательно исключает избыточные абстракции и неявное поведение. Это выгодно как для разработчиков, так и для ИИ, который интерпретирует и генерирует код.

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