Обходной путь для методов final == и != (равно и не равно) в scala DSL

Итак, я оборачиваю части API Mechanical Turk, и вам нужно указать квалификационные требования, такие как:

Worker_Locale == "US"
Worker_PercentAssignmentsApproved > 95
...

В моем коде я хотел бы разрешить приведенный выше синтаксис и перевести его во что-то вроде:

QualificationRequirement("00000000000000000071", "LocaleValue.Country", "EqualTo", "US")
QualificationRequirement("000000000000000000L0", "IntegerValue", "GreaterThan", 95)

Я могу добиться большей части того, что хочу, объявив такой объект, как:

object Worker_PercentAssignmentsApproved {
  def >(x: Int) = {
    QualificationRequirement("000000000000000000L0", "IntegerValue", "GreaterThan", x)
  }
}

Но я не могу сделать то же самое для методов "==" (равно) или "!=" (не равно), так как они объявлены окончательными в AnyRef. Есть ли стандартный обходной путь для этого? Возможно, мне следует просто использовать «===» и «!==» вместо этого?

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

Изменить: обратите внимание, что я не пытаюсь выполнить сравнение на равенство. Вместо этого я пытаюсь наблюдать оператор сравнения, указанный пользователем в коде scala, сохранять объектное описание этого сравнения и передавать это описание серверу. В частности, следующий код scala:

Worker_Locale == "US"

приведет к тому, что к моему запросу будут добавлены следующие параметры:

&QualificationRequirement.1.QualificationTypeId=000000000000000000L0
&QualificationRequirement.1.Comparator=EqualTo
&QualificationRequirement.1.LocaleValue.Country=US

Поэтому я не могу переопределить equals, так как он возвращает Boolean, и мне нужно вернуть структуру, которая представляет все эти параметры.


person Steve    schedule 17.11.2010    source источник


Ответы (3)


Если вы посмотрите на определение == и != в справочнике по scala (§ 12.1), вы обнаружите, что они определены в терминах eq и equals.

eq - это ссылочное равенство, а также final (в этом случае оно используется только для проверки null), но вы должны иметь возможность переопределить equals.

Обратите внимание, что вам, вероятно, также потребуется написать метод hashCode, чтобы гарантировать
∀ o1, o2 с o1.equals(o2)(o1.hashCode.equals(o2.hashCode)).

Однако, если вам нужен какой-либо другой тип возврата для вашего DSL, чем Boolean, или в целом большая гибкость, вам, возможно, следует использовать ===, как это было сделано в Squeryl, например.

person Debilski    schedule 17.11.2010
comment
Я отредактировал вопрос, чтобы было понятнее, что equals здесь действительно не подходит, поскольку он возвращает Boolean. Спасибо за ссылку на Squeryl! - person Steve; 17.11.2010

Вот небольшой обзор того, что различные DSL используют для такого рода вещей.

Liftweb использует === в выражениях Javascript:

JsIf(ValById("username") === value.toLowerCase, ...)

Squeryl использует === для выражений SQL:

authors.where(a=> a.lastName === "Pouchkine")

querydsl использует $eq для выражений SQL:

person.firstName $eq "Ben"

Prolog-in-Scala использует === для выражений Prolog:

'Z === 'A

Scalatest использует === для получения Option вместо Boolean:

assert("hello" === "world")

Поэтому я думаю, что консенсус в основном заключается в использовании ===.

person Steve    schedule 18.11.2010

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

"some string" + <someDslConstruct>

Независимо от того, что вы делаете, это будет выглядеть как что-то вроде

stringToLiteralString("some string" + <someDslConstruct>)

Я думаю, что единственный потенциальный выход из этой ямы — попробовать использовать макросы. В вашем примере, возможно, вы могли бы иметь макрос, который обертывает выражение scala и преобразует необработанный AST в запрос? Выполнение этого для произвольных выражений было бы неосуществимо, но если ваша область достаточно хорошо ограничена, это может быть рабочим альтернативным решением.

person Mumrah    schedule 22.06.2016