Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scala 与 DSL #10

Open
zhongl opened this issue Jul 5, 2013 · 6 comments
Open

Scala 与 DSL #10

zhongl opened this issue Jul 5, 2013 · 6 comments
Labels

Comments

@zhongl
Copy link
Member

zhongl commented Jul 5, 2013

最早结识DSL, 还是因为看了Martin Flower的一篇文章叫FluentInterface, 它真正让我明白原来代码也可以这样美的.

TimeInterval meetingTime = fiveOClock.until(sixOClock);

注意, 本文中提到的DSL被狭义的等同于了Internal DSL. 言外之意, 它还有External的部分. 关于DSL更全面的内容, 还请参阅Martin Flower的专著.

以至于后来我爱上写单元测试, 很大程度要归功于mockitoDSL应用上的如火纯青.

尽管jMock要早于mockito, 而我个人却更喜欢后者.

在自己尝试着用Java写DSL的时候, 那永远摆脱不掉的.(), 总让我纠结不已, 当然, 这只是个人洁癖而已.

Scala在实现DSL是很有优势的, 这在combinator.Parsers中已表明了这点, 而且在Programming Scala一书中, 作者专门用一个章节来讨论.

值得强调的是, 阻碍我们设计实现DSL的是我们自己的想象力, 而不应该是一门语言的表现力.

在此引出本文的目的: 大家来聊聊你用Scala写过的哪些DSL?

@zhongl
Copy link
Member Author

zhongl commented Jul 5, 2013

我在yascli设计了编写命令行应用的DSL, 如:

import com.github.zhongl.yascli._
import com.github.zhongl.yascli.Converters._

object Example extends Command(name = "example", description = "a example of single command") with Application {
    private val flag0       = flag("-f" :: "--flag" :: Nil, "enable flag")
    private val singleValue = option[String]("--single-value" :: Nil, "set single value", "value")
    private val param       = parameter[String]("param", "set param")

    override def run() {
        if (flag0()) println("enable flag0.")
        println(singleValue())
        println(param())
    }
}

最近想要改进, 但感觉自己的想象力有点枯竭, 故拿出来献丑, 求灵感!

@hongjiang
Copy link
Member

我没写过DSL方面的东西,也是从PIS 书中了解到的 parser combinator。 发现scala语言已经内置了,并且提供的接口确实很方便,只要把语义规则想明白了,实现起来非常简洁,背后的算法我完全不用关注(除非要考虑性能)。这点最初很让我震惊,原本以为要很复杂的事情几行代码就可以解决了。

另外也感觉内置的这个parser combinator有些“鸡肋”,主要可能是因为性能问题,比如cobar里用于解析sql的parser,或fastjson里的parser都做了很大优化,稍微要求一点性能的情况下都不太适用。不过这根dsl无关,跑题了。

@zhongl
Copy link
Member Author

zhongl commented Jul 5, 2013

@hongjiang 说到Parser, 这里我推荐parboiled, 据说性能要优于内置的Parser. 不过我倾向于使用Internal DSL, 几乎没有使用它的场景.

@noroot777
Copy link

内部DSL的流程控制该怎么实现呢,纠结

@henix
Copy link

henix commented Dec 26, 2014

我最近写的一个 CSS Selector 的 DSL: https://github.com/henix/ssoup

jsoup 本来是外部 DSL ,即它需要解析一个字符串:

element.select("body > div#page > div#nav");

在看了 jsoup 的代码之后,我发现它实现 selector 效率偏低,每个 selector 都要遍历整个 DOM 树。故自己实现一个内部 DSL,一方面写起来容易,另一方面只访问部分 DOM 节点,效率提升。

val nav = select(body > "div#page" > "div#nav").headOption

这里的 > 是运算符。

另外还写过一个中文单元测试的 DSL http://www.douban.com/note/432612442/ ,其实就是把 ScalaTest 的 it should ... in ... 翻译成中文了。。。

@hongjiang
Copy link
Member

赞啊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants