Безопасная библиотека типов для Scala и Java - PullRequest
4 голосов
/ 14 июня 2011

Ниже приведен типобезопасный, гибкий шаблон компоновщика в Scala, описанный в http://www.tikalk.com/java/blog/type-safe-builder-scala-using-type-constraints. Он похож на Библиотека компоновщика для Scala и Java , но имеет дело с проверками компилятора во время компиляции,Как это можно назвать из Java?Можно ли это сделать с помощью чистого API для Scala AND Java с параметрами "scala.Predef $$ eq $ colon $ eq"?

sealed trait TBoolean
sealed trait TTrue extends TBoolean
sealed trait TFalse extends TBoolean

class Builder[HasProperty <: TBoolean] private(i: Int) {
  protected def this() = this(-1)
  def withProperty(i: Int)(implicit ev: HasProperty =:= TFalse) = new Builder[TTrue](i)
  def build(implicit ev: HasProperty =:= TTrue) = println(i)
}

//javap output
    public class Builder extends java.lang.Object implements scala.ScalaObject{
    public Builder withProperty(int, scala.Predef$$eq$colon$eq); //How is this called from Java?
    public void build(scala.Predef$$eq$colon$eq);
    public Builder();
}
object Builder {
  def apply() = new Builder[TFalse]
}

Ответы [ 2 ]

6 голосов
/ 15 июня 2011

Вы должны иметь возможность использовать этот API из Java, с некоторыми дополнительными помехами по сравнению с версией Scala.Несколько удобных полей немного успокоят:

object Builder {
   def apply() = new Builder[TFalse]
   val unassigned = =:=.tpEquals[TFalse]
   val assigned = =:=.tpEquals[TTrue] 
}

Код клиента Java должен выглядеть так:

Builder$.MODULE$.apply()
   .withProperty(10, Builder$.MODULE$.unassigned())
   .build(Builder$.MODULE$.assigned());

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

Builder$.MODULE$.apply()
   .withProp1(10, Builder$.MODULE$.unassigned())
   .withProp2(20, Builder$.MODULE$.unassigned())
   .withProp3(30, Builder$.MODULE$.unassigned())
   // ...
   .build(Builder$.MODULE$.assigned(), 
          Builder$.MODULE$.assigned(), 
          Builder$.MODULE$.assigned(), 
          //...
         );

С некоторыми статическими делегатами в классе помощника (и некоторыми статическими импортами) вы сможете получить что-то вроде:

createBuilder()
   .withProp1(10, unassigned())
   .withProp2(20, unassigned())
   .build(assigned(), assigned());
3 голосов
/ 17 июня 2011

ОК, спасибо Аарону и Иттаиду ... вот сборщик с плавным API для Scala и Java:

import annotation.bridge

sealed trait TBoolean
sealed trait TTrue extends TBoolean
sealed trait TFalse extends TBoolean

class Builder[HasProperty <: TBoolean] private(i: Int) {
  protected def this() = this(-1)

  def withProperty(i: Int)(implicit ev: HasProperty =:= TFalse) = new Builder[TTrue](i)
  def build(implicit ev: HasProperty =:= TTrue):Int = i
  @bridge def withProperty(i: Int) = new Builder[TTrue](i)
  @bridge def build = build(null)
}

object Builder {
  def apply() = new Builder[TFalse]
  val unassigned = =:=.tpEquals[TFalse]
  val assigned = =:=.tpEquals[TTrue]
}

Использование Scala (Тип Сейф):

val v = Builder().withProperty(2).build

Java Использование I (тип безопасно, но безобразно):

int i = Builder$.MODULE$.apply()
        .withProperty(5, Builder$.MODULE$.unassigned())
         .build(Builder$.MODULE$.assigned()); 

Java Usage II (небезопасно, но намного чище при использовании вызовов @Bridge):

static Builder createBuilder() {
  return Builder$.MODULE$.apply();
}
...
int j = createBuilder().withProperty(7).build();
...