Обходной путь для окончательных == и! = (равно и не равно) методов в Scala DSL - PullRequest
2 голосов
/ 17 ноября 2010

Итак, я обертываю биты 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, сохранить описание этого сравнения на основе объектов и передать это описание на сервер. В частности, следующий код скалы:

Worker_Locale == "US"

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

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

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

Ответы [ 3 ]

4 голосов
/ 17 ноября 2010

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

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

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

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

3 голосов
/ 18 ноября 2010

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

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

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

Скверил использует === для выражений 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")

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

0 голосов
/ 22 июня 2016

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

.
"some string" + <someDslConstruct>

Неважно, что вы делаете, это будет звучать как

stringToLiteralString("some string" + <someDslConstruct>)

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

...