Создание библиотеки протоколов и defrecords для использования с Java

На данный момент у меня есть полностью функциональная библиотека Clojure, которая вызывается из Java.

То, как я это делаю: у меня есть файл, который использует gen-class для обертывания всего API как статических методов одного класса и передает данные в виде IPersistentVector и IPersistentMap.

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

У меня есть четыре протокола, давайте назовем их A, B, C и D. И два defrecords, X и Y. X и Y реализуют протоколы A, B и C. Хотя Y также реализует D.

Что мне нужно сделать, чтобы сделать их доступными для Java? Доступны ли они автоматически как интерфейсы и классы? Или мне еще нужно сделать эквивалент gen-класса, чтобы сделать их общедоступными?

Если нет, то что эквивалентно предложению gen-class: methods, где я определяю типы Java для аргументов методов?

Есть ли у кого-нибудь простой пример обеспечения доступности протоколов и записей Java?

Ответ 1

defprotocol

Каждый Clojure протокол также является интерфейсом Java с тем же именем и методами. Если я приведу пример из ibm developerworks, мы увидим, что:

(ns com.amalgamated)

(defprotocol Fulfillment
  (invoice [this] "Returns an invoice")
  (manifest [this] "Returns a shipping manifest"))

Является эквивалентным:

package com.amalgamated;

public interface Fulfillment {
    public Object invoice();
    public Object manifest();
}

Clojure.org также содержит некоторую (довольно краткую) информацию об этом.

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

(extend AType   AProtocol   
 {:foo an-existing-fn
    :bar (fn [a b] ...)
    :baz (fn ([a]...) ([a b] ...)...)}   BProtocol
    {...} ...)

definterface

Если вы нацелены на производительность, вы можете рассмотреть возможность использования definterface, использование которого аналогично протоколам. Этот сообщение SO также содержит сведения о том, как его использовать:

(definterface Foo
  [^int foo [x ^String y]]
  [^void bar [^ints is]])

definterface кажется быстрее, чем протоколы.

defrecord

Аналогично, record (а также deftype и definterface) будут генерировать Java-классы. Опять же, Clojure.org/datatypes имеет полезную информацию (внимание мое):

deftype и defrecord динамически генерирует скомпилированный байт-код для с именем class с набором заданных полей и, необязательно, методов для один или несколько протоколов и/или интерфейсов. Они подходят для динамического и интерактивное развитие, не нужно компилировать AOT, и может быть переоценена в ходе одного сеанса. Они похожи на defstruct в создании структур данных с именованными полями, но отличаются из defstruct в том, что: [...]

Итак, да, если будет доступно с Java. Просто будьте осторожны с наименованием.

В качестве дополнительной заметки вы можете захотеть взглянуть на вызов Clojure из Java.