Skip to content

Commit 6678527

Browse files
update
1 parent f352a84 commit 6678527

File tree

1 file changed

+145
-1
lines changed

1 file changed

+145
-1
lines changed

website/blog/yaml-vs-dsl.md

Lines changed: 145 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ ast-grep does support pattern. It is a concept to match a strcture that contains
4040

4141
> your documentation, where you have to extensively explain how pattern syntax works, how pattern syntax works, how metavariables work
4242
43-
As stated before, pattern makes ast-grep users' life easier. Explaining how pattern works is necessary to help users understand how to write rules. This is not a sign of a DSL being necessary, but rather a sign of the limitation of pattern: it is not general enough to cover all cases, and you have to communicate to your users how pattern works in your system. For example, see this [tweet](https://x.com/hd_nvim/status/1941876968363798766) about how to write a pattern to match `functtion` declation in JavaScript.
43+
As stated before, pattern makes ast-grep users' life easier. Explaining how pattern works is necessary to help users understand how to write rules. This is not a sign of a DSL being necessary, but rather a sign of the limitation of pattern: it is not general enough to cover all cases, and you have to communicate to your users how pattern works in your system. For example, see this [tweet](https://x.com/hd_nvim/status/1941876968363798766) about how to write a pattern to match `function` declation in JavaScript. Another brain teaser, how to tell if `$a = $b` is an `assignment_expression` or `field_initializer`?
4444

4545
(an [ad-hominen](https://en.wikipedia.org/wiki/Ad_hominem) note: it is ironic to see this argument from a tool without proper documentation. I cannot suspend my suspect whether the author has used pattern to write non-trivial rules at all.)
4646

@@ -59,3 +59,147 @@ This is a subjective opinion, instead of an fundamental blocker. The author fail
5959
We can also see using DSL is not subjectively better than YAML as well.
6060

6161
## Subjective Comparison of DSL
62+
63+
Let's review the DSL mentioned above.
64+
65+
### Mix of several different paradigms
66+
67+
Biome's DSL is a mix of several different paradigms: declarative, logic, and imperative. Let's see one example:
68+
69+
```JavaScript
70+
`$method($message)` where {
71+
$method <: `console.log`,
72+
if ($message <: r"Hello, .*!") {
73+
$linter = "hello world"
74+
} else {
75+
$linter = "not hello"
76+
},
77+
register_diagnostic(
78+
span = $method,
79+
message = $linter
80+
)
81+
}
82+
```
83+
84+
* `$method('$message')` is a declarative pattern matching syntax.
85+
* `where` and `<:` are related to [logic programming](https://en.wikipedia.org/wiki/Logic_programming#:~:text=Logic%20programming%20is%20a%20programming,solve%20problems%20in%20the%20domain.) paradigm, say, [Prolog](https://en.wikipedia.org/wiki/Prolog) or SQL.
86+
* `if` is a typical imperative programming paradigm
87+
88+
The mixture of paradigms does not blend well. At least, in the eye of a programming language veteran, it is too messy for a DSL for linting or structural search. We are not designing a next-era programming language.
89+
90+
### Easy to miss comma
91+
92+
Did you notice there is two trailing commas in `$method <: console.log` and if block?
93+
94+
```JavaScript{2,7}
95+
`$method($message)` where {
96+
$method <: `console.log`, // [!code focus]
97+
if ($message <: r"Hello, .*!") {
98+
$linter = "hello world"
99+
} else {
100+
$linter = "not hello"
101+
}, // [!code focus]
102+
register_diagnostic(
103+
span = $method,
104+
message = $linter
105+
)
106+
}
107+
```
108+
109+
Without them you will get a syntax error. This is a common problem for beginners to miss commas, a typical pitfall only in DSL. Alas, I can still remeber the old day when C compiler complained about missing semicolon.
110+
111+
### Similar basic patterns have distinct syntax appearance
112+
113+
There are several different basic patterns in the DSL. Though they are at the similar level of abstraction, their appearance is totally different.
114+
115+
```JavaScript
116+
`console.log($foo)` // pattern
117+
augmented_assignment_expression(operator = $op, left = $x, right = $v) // syntax node
118+
r"Hello, (.*)"($name) // regex
119+
```
120+
121+
These patterns are corresponding to `pattern`, `kind` and `regex` in ast-grep. However, they look totally different. You need more learning to pick up these distinct syntax.
122+
123+
### Similar syntax appearance have different meaning
124+
125+
One common pitfall to design DSL is that similar syntax have different meaning.
126+
127+
```JavaScript
128+
// this is a syntax node call
129+
augmented_assignment_expression(operator = $op)
130+
pattern console_method_to_info($method) {
131+
`console.$method($message)` => `console.info($message)`
132+
}
133+
// this is a pattern call
134+
console_method_to_info(method = `log`)
135+
predicate program_contains_logger() {
136+
$program <: contains `logger`
137+
}
138+
// this is a predicate call
139+
program_contains_logger()
140+
141+
// define a lines function
142+
function lines($string) {
143+
return split($string, separator=`\n`)
144+
}
145+
// this is a function call
146+
lines(string = $message)
147+
```
148+
149+
They all look like function calls, but they are not. See explanation below for the differences.
150+
151+
### Confusing Concepts of `pattern`, `predicate` and `function`
152+
153+
These three concepts are very similar, but they have slightly different usage in the DSL.
154+
155+
* `pattern` is used in `<:` or somewhere else, I dunno, the doc does not explain it well.
156+
* `predicate` is used in `where` condition.
157+
* `function` is used in `assignment`, `insertion` or `rewrite`.
158+
159+
Example:
160+
161+
```JavaScript
162+
`console.log` => `logger.info` where {
163+
$program <: contains_logger(), // pattern
164+
program_contains_logger(), // equivalent predicate
165+
$program => replace_logger(), // function
166+
}
167+
```
168+
169+
### Confusing Concepts of `condition`, `clause` and `modifier`
170+
171+
The DSL also has three similar concepts: `condition`, `clause` and `modifier`.
172+
Introduced in different places, [here](https://docs.grit.io/language/conditions) and [here](https://docs.grit.io/language/modifiers), without clear definition.
173+
174+
### Similar patterns but applied in different places
175+
176+
Tell the difference between [and](https://docs.grit.io/language/modifiers#and-clause), [any](https://docs.grit.io/language/modifiers#any-clause), [some](https://docs.grit.io/language/modifiers#some-clause) and [every](https://docs.grit.io/language/modifiers#every-clause).
177+
Confusing? You should learn the difference between meta var in [list pattern](https://docs.grit.io/language/modifiers#list-patterns) and plain meta var. Also, don't confuse list meta var with [spread meta var](https://docs.grit.io/language/patterns#metavariables)
178+
179+
### One more thing, variable scope.
180+
181+
If you still have patience, you need one last thing to learn: variable scope.
182+
183+
I have no better explanation for it since I don't understand it well, so I will quote the [official documentation](https://docs.grit.io/language/bubble):
184+
185+
> Once a metavariable is bound to a value, it retains this value throughout the target code. Therefore, the scope of the metavariable spans the entire target file.
186+
187+
To fully understand it, you also need to know `bubble`, `bubble($argument)` and pattern auto wrap.
188+
189+
190+
## Conclusion
191+
192+
If you also feel confused, you are not alone. Again, the preference of DSL over YAMl is largely subjective.
193+
194+
If you think DSL is better, you are right. [You are absolutely right](https://www.reddit.com/r/ClaudeAI/comments/152b51r/you_are_absolutely_right/). In fact, you are [not even wrong](https://en.wikipedia.org/wiki/Not_even_wrong). Since this is a subjective opinion, not an objective fact.
195+
196+
If you are a library or framework author, you can make decision based on your own preference. However, mistakenly thinking your preference is objective will lead to confusion and misunderstanding. It may even reflect inferior tech taste and judgement.
197+
198+
Consider these points when you want to have objective comparison:
199+
200+
* Documentation?
201+
* User Education? Howe you teach users to write your DSL?
202+
* Tooling support like [playground](/playground.html).
203+
* Editor support beyong syntax highlighting. Say LSP.
204+
* Integration with API, how you bring type-safe DSL into your general purpose programming language, like [graphql](https://github.com/Quramy/ts-graphql-plugin) and [styled component](https://github.com/styled-components/typescript-styled-plugin).
205+
* Broader ecosystem support, such as GitHub language detection, AI support, etc.

0 commit comments

Comments
 (0)