24.1. Wewnętrzne DSL
Wewnętrzny język dostosowany do dziedziny (ang. internal Domain Specific Language, w skrócie internal DSL), jest swego rodzaju językiem utworzonym na bazie składni innego języka (na przykład języka Scala) i zapisywanym w tym języku i zgodnie z wymogami jego składni, ale jednocześnie jest zaprojektowany w taki sposób, aby przypominał jakiś odrębny język, zawierający właściwe sobie konstrukcje. Opisane w tym rozdziale przykłady prezentują zarówno proste DSL, implementujące pojedyncze instrukcje lub wyrażenia, jak i bardziej rozbudowany DSL, służący do budowania wyrażeń opisujących instrukcje manipulujące obrazami graficznymi zapisanymi w plikach.
Jako pierwszy przykład, w pliku Factorial.scala, przedstawiona jest implementacja operatora ! obliczającego silnię liczby całkowitej.
Plik Factorial.scala: import scala.language.implicitConversions object Factorial { implicit class FactorialWrapper(val n: Int) extends AnyVal { def ! = (1 to n).product } }
W celu wykorzystania tego operatora należy wykonać dwie instrukcje import: pierwsza z nich importuje implementację operatora, a druga zezwala na użycie postfiksowych operatorów, co jest wymagane, gdyż operator obliczający silnię użyjemy właśnie jako operator postfiksowy. Po dokonaniu importów można wykorzystywać ten operator w sposób pokazany w poniższym przykładzie.
scala> import Factorial._ import Factorial._ scala> import scala.language.postfixOps import scala.language.postfixOps scala> 4! res0: Int = 24 scala> 1! res1: Int = 1
Dzięki temu, że Scala pozwala na używanie identyfikatorów w postaci operatorów możliwe jest zdefiniowanie metody o nazwie !. Dzięki temu, że zdefiniowana metoda jest bezparametrowa oraz dzięki wykorzystaniu operacji postfiksowej możliwe jest wywołanie tej metody poprzez proste dopisanie jej nazwy do obiektu. Wreszcie niejawna konwersja z typu Int na typ Factorial zaimplementowana za pomocą klasy z modyfikatorem implicit pozwala na używanie tej metody na obiekcie typu Int. Dzięki użyciu klasy wartości unikamy ponadto dodatkowego narzutu w postaci tworzenia obiektu-opakowania.