Существует ли язык программирования, специально разработанный для внедрения зависимостей?


21

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

Существует ли какой-либо язык, специально разработанный для упрощения внедрения зависимостей и, наоборот, для создания скрытых зависимостей?

Разъяснение:

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

Я не ищу рекомендации по языку. Это исторический вопрос. Кто-нибудь из авторов языка явно намеревался сделать это?


1
Сильно связаны, если не полностью дублируют: как можно внедрить внедрение зависимости в язык?
Роберт Харви

Whee! 3K! Теперь я могу наблюдать за их голосованием, чтобы закрыть этот вопрос. :) Спасибо за голоса.
candied_orange

1
Вы должны прочитать этот пост в любом случае. «Существует ли это» - гораздо менее интересный вопрос, если вы не расширите его до чего-то вроде «как они это сделали?»
Роберт Харви

1
Будет ли Haskell считать? С помощью функций каррирования и высших порядков вы можете решить большинство проблем, которые DI обычно решает на языках ООП, и из-за его строгости в отношении чистоты вы вынуждены отделять побочные эффекты, такие как IO и т. Д., И функции не могут волшебным образом вызвать то, что они не передали в качестве аргумента. Вы не получаете никакого соглашения по конфигурации, но с другой стороны, я постепенно отхожу от этого даже в моем коде ООП в настоящее время, так как я заметил, что большинству команд нельзя доверять это в проектах среднего размера и более крупных.
wasatz

1
@wasatz: Да, Хаскелл считает. Большинство «программных паттернов» - это всего лишь обходные пути для недостатков в языке программирования.
Роберт Харви

Ответы:


21

Да, это действительно так. Вроде.

Newspeak не имеет статического состояния и глобального состояния. Это означает, что единственный возможный способ получить доступ к зависимости - это ввести ее явно. Очевидно, это означает, что язык или, в случае Newspeak, более точно, IDE должен облегчить внедрение зависимостей, в противном случае язык будет непригодным для использования.

Таким образом, язык не предназначен для DI, скорее необходимость в DI является следствием языкового дизайна.

Если нет статического состояния и нет глобального состояния, то вы не можете просто «достучаться» до эфира и что-то вытянуть. Например, в Java структура пакета является статическим состоянием. Я могу просто сказать, java.lang.Stringи у меня есть сам Stringкласс. Это невозможно в Newspeak. Все, с чем вы работаете, должно быть явно предоставлено вам, иначе вы просто не сможете этого достичь. Итак, все является зависимостью, и каждая зависимость является явной.

Вы хотите строку? Ну, вы должны сначала попросить stdlibобъект передать вам Stringкласс. О, но как вы получаете доступ к stdlib? Ну, вы должны сначала попросить platformпередать вам stdlibобъект. О, но как вы получаете доступ к platform? Ну, вы должны сначала попросить кого-то еще передать вам platformобъект. О, но как вы можете получить доступ к этому кто-то, что есть? Что ж, вы должны сначала попросить еще кого-нибудь передать вам объект.

Как далеко это заходит в кроличью нору? Где останавливается рекурсия? Вообще-то, на самом деле. Это не останавливает. Тогда как вы можете написать программу в Newspeak? Ну, строго говоря, вы не можете!

Вам нужна какая-то внешняя сущность, которая связывает все это вместе. В Newspeak эта сущность является IDE. IDE видит всю программу. Это может связать разрозненные части вместе. Стандартный шаблон в Newspeak состоит в том, что в центральном классе вашего приложения есть platformметод доступа , а IDE Newspeak внедряет в этот метод объект, который имеет методы, которые возвращают некоторые основные потребности программирования: Stringкласс, Numberкласс, Arrayкласс, и так далее.

Если вы хотите протестировать свое приложение, вы можете внедрить platformобъект, Fileметод которого возвращает класс с помощью фиктивных методов. Если вы хотите развернуть свое приложение в облаке, вы внедряете платформу, Fileкласс которой фактически поддерживается Amazon S3. Кроссплатформенные графические интерфейсы работают путем внедрения различных структур графического интерфейса для разных ОС. У Newspeak даже есть экспериментальный компилятор Newspeak-to-ECMAScript и среда графического интерфейса с HTML-поддержкой, которая позволяет переносить полнофункциональное приложение с графическим интерфейсом пользователя с собственного рабочего стола в браузер без изменений, просто добавляя различные элементы графического интерфейса.

Если вы хотите развернуть свое приложение, IDE может сериализовать приложение в объект на диске. (В отличие от своего предшественника, Smalltalk, Newspeak имеет формат сериализации объектов вне изображения. Вам не нужно брать с собой все изображение именно потому, что все зависимости внедрены: IDE точно знает , какие части системы ваше приложение использует, а что нет. Таким образом, он сериализует в точности подключенный подграф объектного пространства, составляющего ваше приложение, и ничего более.)

Все это работает просто, доводя объектную ориентацию до крайности: все является вызовом виртуального метода («отправка сообщения» в терминологии Smalltalk, потомком которого является Newspeak). Даже поиск суперкласса - это вызов виртуального метода! Возьми что-то вроде

class Foo extends Bar // using Java syntax for familiarity

или в Newspeak:

class Foo = Bar () () : ()

В Java это создаст имя Fooв статическом глобальном пространстве имен, и будет искать Barв статическом глобальном пространстве имен и создать Bar Fooсуперкласс. Даже в Ruby, который гораздо более динамичен, это все равно создаст статическую константу в глобальном пространстве имен.

В Newspeak эквивалентное объявление означает: создайте именованный метод getter Fooи заставьте его вернуть класс, который ищет свой суперкласс, вызвав метод named Bar. Примечание: это не похоже на Ruby, где вы можете поместить любой исполняемый код Ruby в качестве объявления суперкласса, но код будет выполнен только один раз при создании класса, и возвращаемое значение этого кода станет фиксированным суперклассом. Нет. Метод Barвызывается для каждого поиска метода!

Это имеет некоторые глубокие последствия:

  • поскольку миксин в основном является классом, который еще не знает своего суперкласса, а в Newspeak суперкласс является динамическим вызовом виртуального метода, и, следовательно, неизвестен, каждый класс автоматически также является миксином. Вы получаете миксины бесплатно.
  • поскольку внутренний класс - это просто вызов метода, который возвращает класс, вы можете переопределить этот метод в подклассе внешнего класса, поэтому каждый класс является виртуальным. Вы получаете виртуальные занятия бесплатно:

    class Outer {
      class Inner { /* … */ }
    }
    
    class Sub extends Outer {
      override class Inner { /* … */ }
    }
    

    новояз:

    class Outer = () (
      class Inner = () () : ()
    ) : ()
    
    class Sub = Outer () (
      class Inner = () () : ()
    ) : ()
    
  • Поскольку суперкласс является просто вызовом метода, который возвращает класс, вы можете переопределить этот метод в подклассе внешнего класса, у внутренних классов, определенных в суперклассе, может быть другой суперкласс в подклассе. Вы получаете наследование иерархии классов бесплатно:

    class Outer {
      class MyCoolArray extends Array { /* … */ }
    }
    
    class Sub extends Outer {
      override class Array { /* … */ }
      // Now, for instances of `Sub`, `MyCoolArray` has a different superclass 
      // than for instances of `Outer`!!!
    }
    

    новояз:

    class Outer = () (
      class MyCoolArray = Array () () : ()
    ) : ()
    
    class Sub = Outer () (
      class Array = () () : ()
    ) : ()
    
  • и, наконец, самое важное для этого обсуждения: поскольку (кроме тех, которые вы определили в своем классе, очевидно) вы можете вызывать методы только в своем лексически включающем классе (ах) и своем суперклассе (ах), самом внешнем классе верхнего уровня. не может вызывать любые методы на всех , кроме тех, которые явно инжектированные: класс верхнего уровня не имеет класса ограждающих методы которого он мог бы назвать, и она не может иметь суперкласса, кроме одного по умолчанию, потому что объявление суперкласса является вызов метода, и это , очевидно , не может перейти к суперклассу (это являетсясуперкласс), и он также не может перейти в лексически заключенный класс, потому что его нет. Это означает, что классы верхнего уровня полностью инкапсулированы, они могут получить доступ только к тому, что им явно вводят, и им вводят только то, что они явно запрашивают. Другими словами: классы верхнего уровня являются модулями. Вы получаете всю систему модулей бесплатно. Фактически, чтобы быть более точным: классы верхнего уровня являются объявлениями модулей, его экземпляры являются модулями. Таким образом, вы получаете модульную систему с параметрическими объявлениями модулей и первоклассными модулями бесплатно, что многие, даже очень сложные, модульные системы не могут сделать.

Чтобы сделать все эти инъекции безболезненными, объявления классов имеют необычную структуру: они состоят из двух объявлений. Одним из них является конструктор класса, который является не конструктором, который создает экземпляры класса, а конструктором, который создает среду, в которой выполняется тело класса. В Java-подобном синтаксисе это будет выглядеть примерно так:

class Foo(platform) extends Bar {
  Array  = platform.collections.Array
  String = platform.lang.String
  File   = platform.io.File
| // separator between class constructor and class body
  class MyArray extends Array { /* … */ }
  // Array refers to the method defined above which in turn gets it from the 
  // platform object that was passed into the class "somehow"
}

новояз:

class Foo using: platform = Bar (
  Array = platform collections Array
  String = platform streams String 
  File = platform files ExternalReadWriteStream
) (
  class MyArray = Array () () : ()
) : ()

Обратите внимание, что способ, которым программист Newspeak действительно собирается увидеть класс (ы), выглядит следующим образом:Newspeak IDE отображает несколько вложенных классов

Я даже не могу начать делать это справедливо. Вам придется поиграть с этим самостоятельно. Гилад Брача выступил с парой докладов о различных аспектах системы, в том числе о модульности. Он дал очень длинную (2 часа) речь , первый час которой - подробное введение в язык, включая историю модульности. Глава 2 платформы программирования Newspeak посвящена модульности. Если вы просматриваете Newspeak на Squeak - Руководство для недоумевающих (aka Newspeak-101) , вы почувствуете систему. Newspeak by Example - это живой документ (т.е. он работает внутри порта Newspeak-on-ECMASCript, каждая строка кода редактируема, каждый результат проверяем), демонстрирующий основной синтаксис.

Но на самом деле, вы должны поиграть с этим. Он настолько отличается от всех основных и даже неосновных языков, что его трудно объяснить, его нужно испытать.


3
Мех. Запретите использование статического состояния и глобального состояния, и это можно сказать практически о любом современном языке программирования.
Роберт Харви

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

@ Йорг. Как-нибудь еще можно поддержать этот ответ? Я погуглил «внедрение зависимостей newspeaklanguage.org» и вышел пустым. Самое близкое, что я мог найти, было это: news.ycombinator.com/item?id=9620561
candied_orange

@CandiedOrange: Я находился в процессе расширения ответа, но потом вмешался «реальный мир». Это лучше?
Йорг Миттаг

3
@ JörgWMittag Святое дерьмо! Ну, это, конечно, «больше». Держись, пока я оцениваю «лучше». Может потребоваться сила посещения ванной, чтобы пройти через это.
candied_orange

7

Язык Wake Programming разработан для использования внедрения зависимостей. По сути, он имеет эквивалент структуры внедрения зависимостей, встроенной в сам язык. Классы определяют параметры, которые они needи provideкомпилятор подключают все.


6

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

public interface I {
    void something ();
)

public class Concrete implements I {
    public void something () { ... }
}

public class Client {
    I myI;
    public Client (I injected) { myI = injected; }
    ...
}

...

    Client c = new Client (new Concrete());
    ...

и заменить Клиента и его использование на:

public class Client {
   I myI = new I();
   ...
}

   Client c = new Client { I -> Concrete } ();

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


Интересный. Это напоминает мне Типы членов Scala, которые также могут быть переопределены в подклассах и оставлены абстрактными в суперклассе. Члены абстрактного типа в сочетании с аннотациями самостоятельного типа составляют основу подхода Scala к модульности и внедрению зависимостей. Меня нисколько не удивляет, что на эту статью ссылались Мартин Одерски , дизайнер Scala, и Гилад Брача , дизайнер Newspeak.
Йорг Миттаг

0

Я не использовал его, но официальный слоган языка программирования Plastic звучит так: « Что произойдет, если вы сделаете инъекцию зависимостей и запустите ее на язык программирования? ». Кажется довольно интересным

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.