A funkcionális irányból megközelítve a dolgot, egy osztályt úgy tudunk kiegészíteni, hogy plusz függvényeket készítünk hozzá.
Ha a link-nél is szereplő String kiegészítéseket akarnánk megcsinálni, akkor azt így tehetnénk meg funkcionálisan:
object StringImprovements {
def increment(s: String) = s.map(c => (c + 1).toChar)
def decrement(s: String) = s.map(c => (c − 1).toChar)
def hideAll(s: String) = s.replaceAll(".", "*")
}
Így tudnánk használni, pl.
StringImprovements.increment("HAL")
Ha beimportáljuk a StringImprovements-et,
import StringImprovements._
akkor így:
increment("HAL")
Kiegészítésnek még majdnem elmenne, de szép DSL-re nem tudnánk használni.
Itt jön az ötlet! Mi lenne, ha az object-ek (singleton) metódusait metódus(PARAM1, PARAM2, ...)
helyett ilyen alakokban is meg lehetne hívni: PARAM1.metódus(PARAM2, ...)
, tehát mintha az első paraméternek lenne a metódusa, illetve, ha maximum két paramétere van, akkor a fentiek alapján így is: PARAM1 metódus PARAM2
. Ezzel elhagyható lenne az implicit konverzió és a függvényeket is használhatnánk DSL-ként.
Az első példát ilyen módokon is hívhatnánk:
"HAL".increment
"HAL" increment
, tehát pontosan úgy, mint implicit konverzió esetén.
Ha pl. akarunk egy olyan függvényt készíteni, ami egy egész listát leszűr egy adott egész számnál nagyobbakra.
def greaterThan(numbers: List[Int], number: Int) = numbers.filter(_ > number)
, akkor azt így is meg tudnánk hívni:
val numbers = List(1, 9, 3, 6, 4, 2, 5)
val numbersGreaterThan4 = numbers greaterThan 4
Két további előnye is van:
- A fordítónak egyszerűbb dolga van, mint az implicit konverziónál. Implicit konverziónál, ha a.f(b) formula nem fordul, akkor körbe kell néznie az összes implicit konverziós osztályban, hogy van-e valamelyikben f metódus. Ez elég lassú és kérik is, hogy minél kevesebb implicit konverziós osztályt használjunk éppen ezért. A mi esetünkben viszont a fordítónak elég megnéznie, hogy az f(a, b) függvény létezik-e, ami nagyon gyors.
- Az implicit konverziós osztálynál előbb létre kell hozni az adott osztályt, majd meghívni egy metódusát. A mi esetünkben kimarad az osztály létrehozás, elég csak a metódust futtatni. Így a futás is valamelyest gyorsabb, mint implicit konverziónál.
Örömmel veszem a véleményeket!
- enpassant blogja
- A hozzászóláshoz be kell jelentkezni
- 713 megtekintés
Hozzászólások
Kezdő vagyok a témában, úgyhogy ez inkább kérdés mint válasz.
A "PARAM1" is csak egy függvény, mint minden más, ahogy az első könyvemből kivettem. Azt a típust kellene kiegészítened a kívánt fügvényekkel és program indításnál felülírni a ClassLoader-ben az eredetit a tiéddel.
"HAL".increment esetén plusz függvényt írsz, "HAL" increment meg csak egy operator overload.
Szóval szerintem erre nincs nyelvi megoldás.
- A hozzászóláshoz be kell jelentkezni
Azt hiszem szokás szerint nem voltam teljesen világos.
Egy új Scala fordítóprogrambeli feature-t szerettem volna felvetni, tehát, hogy milyen jó volna, ha a Scala fordító tudná ezt is, így az implicit konverziót el lehetne felejteni, valamint a függvényeket is be lehetne fogni a DSL definiálásába.
Ez inkább haladó Scala-soknak szól.
- A hozzászóláshoz be kell jelentkezni
edit:
ok, hülye módon nem olvastam el a linkelt cikket. A lenti példa van ott is.
Egy objektum metódusa egy függvény, aminek az első paramétere implicit, neve `this`.
Implicit paraméterek mellett implicit osztályokat is lehet használni DSL-hez:
object StringImprovements {
implicit class StringEx(s: String) {
def increment = s.map(c => (c + 1).toChar)
def decrement = s.map(c => (c - 1).toChar)
def hideAll = s.replaceAll(".", "*")
}
}
object StringTest extends App {
import StringImprovements._
println("hello".increment)
println("hello".decrement)
println("hello".hideAll)
}
- A hozzászóláshoz be kell jelentkezni
+1
- A hozzászóláshoz be kell jelentkezni