OILS / doc / language-influences.md View on Github | oilshell.org

406 lines, 268 significant
1---
2default_highlighter: oils-sh
3---
4
5YSH Language Influences
6=======================
7
8Almost all syntax in YSH comes from another language. This doc lists some of
9these influences.
10
11Reading this page isn't essential for all users, but it may help some users
12remember the syntax.
13
14<div id="toc">
15</div>
16
17## General Philosophy
18
19At a high level, YSH is a bash-compatible shell language that adds features
20from popular dynamic languages.
21
22Its design is more conservative than that of other alternative shells. Our
23goals are to:
24
25- **Preserve** what works best about shell: processes, pipelines, and files.
26- **Clean up** the sharp edges like quoting, ad hoc parsing and splitting
27- **Integrate** features from Python, JavaScript, Ruby, and other languages
28 listed below.
29
30## Major Influences
31
32### POSIX Shell
33
34The command and word syntax comes from shell:
35
36 ls | wc -l # pipeline
37 echo $var "${var} $(hostname)" # variable and command sub
38 echo one; echo two # sequence of commands
39 test -d /tmp && test -d /tmp/foo # builtins and operators
40
41Shell-like extensions in YSH:
42
43 echo $[42 + a[i]] # Expression substitution
44 cd /tmp { echo hi } # Block arguments
45
46### bash and ksh
47
48We implement many bash semantics, like "named references" for out variables:
49
50 f() {
51 local -n out=$1 # -n for named reference
52 out=bar
53 }
54
55 x=foo
56 f x
57 echo x=$x # => x=bar
58
59Though we discourage dynamic scope. YSH provides a better mechanism called
60`value.Place`.
61
62 proc f(; out) {
63 call out->setValue('bar')
64 }
65
66 var x = 'foo'
67 f (&x) # pass a place
68 echo x=$x # => x=bar
69
70<!--
71Historical note: Usenix 93. korn shell was used for GUIs and such!
72-->
73
74### Python
75
76The YSH expression language is mostly Python compatible. Expressions occur on
77the right-hand side of `=`:
78
79 var a = 42 + a[i]
80 var b = fib(10)
81 var c = 'yes' if mybool else 'no'
82
83Proc signatures take influence from Python:
84
85 proc mycopy(src, dest='/tmp') { # Python-like default value
86 cp --verbose $src $dest
87 }
88
89Related: differences documented in [YSH Expressions vs.
90Python](ysh-vs-python.html).
91
92---
93
94J8 strings often have a leading letter, similar to Python's syntax:
95
96 var raw_str = r'C:\Program Files\'
97 var unicode = u'mu = \u{03bc}'
98 var bytes = b'\yfe \yff'
99
100---
101
102The syntax of type objects is similar to Python's syntax:
103
104 parser (&spec) {
105 flag --source (List[Str]) # List[Str] is a type object
106 }
107
108(Though YSH always capitalizes type names.)
109
110### JavaScript
111
112YSH uses JavaScript's dict literals:
113
114 var d1 = {name: 'Alice', age: 10} # Keys aren't quoted
115
116 var d2 = {[mystr]: 'value'} # Key expressions in []
117
118 var name = 'Bob'
119 var age = 15
120 var d3 = {name, age} # Omitted values taken from surrounding scope
121
122Blocks use curly braces, so most code resembles C / Java / JavaScript:
123
124 if (x > 0) {
125 echo 'positive'
126 } else {
127 echo 'zero or negative'
128 }
129
130 var i = 5
131 while (i > 0) {
132 echo $i
133 setvar i -= 1
134 }
135
136### Ruby
137
138YSH has Ruby-like blocks:
139
140 cd /tmp {
141 echo $PWD # prints /tmp
142 }
143 echo $PWD
144
145### Perl
146
147The `@` character comes from Perl (and PowerShell):
148
149 var myarray = :| one two three |
150 echo @myarray # @ is the "splice" operator
151
152 echo @[arrayfunc(x, y)]
153
154 for i in @(seq 3) { # split command sub
155 echo $i
156 }
157
158<!--
159The unbuffered `for` loop is similar to Perl's `while (<>) { ...`:
160
161 for line in <> {
162 echo $line
163 }
164-->
165
166Perl can be viewed as a mixture of shell, awk, and sed. YSH is a similar
167agglomeration of languages, but it's statically parsed.
168
169### Julia
170
171The semicolon in `proc` and `func` definitions comes from Julia:
172
173 func f(x, y; invert=false) {
174 if (invert) {
175 return (-x - y)
176 } else {
177 return (x + y)
178 }
179 }
180
181Multiline strings in YSH strip leading whitespace, similar to Julia:
182
183 proc p {
184 # Because leading and trailing space are stripped, this is 2 lines long
185 var foods = '''
186 peanut
187 coconut
188 '''
189 }
190
191
192(Julia has something like blocks too.)
193
194### Go
195
196Like Go, Oils is UTF-8-centric. (Go blog: [Strings, bytes, runes and
197characters in Go](https://go.dev/blog/strings).)
198
199The design of for loops is roughly influenced by Go:
200
201 for i, item in (mylist) { # ask for index and value
202 echo "$i $item"
203 }
204
205 for i, k, v in (mydict) { # ask for index, key, and value
206 echo "$i $k $v"
207 }
208
209### Awk
210
211YSH gets its regex match operator from Awk:
212
213 if (mystr ~ /digit+/) {
214 echo 'Number'
215 }
216
217(We don't use Perl's `=~` operator.)
218
219### Lisp
220
221YSH has "quotation types" that represent unevaluated code. Like Lisp, they
222give you control over evaluation:
223
224 var my_cmd = ^(ls /tmp | wc -l)
225 eval (my_cmd)
226
227 var my_expr = ^[42 + a[i]]
228 var v = evalExpr(my_expr)
229
230 var my_template = ^"hi $name" # unimplemented
231
232### Haskell
233
234YSH also uses `++` to concatenate strings and lists:
235
236 var mystr = a ++ b
237 var mystr = "$a$b" # very similar
238
239 var mylist = c ++ d
240 var mylist = :| @c @d | # also converts every element to a string
241
242YSH has a `value.IO` type that makes functions pure:
243
244 func renderPrompt(io) {
245 return (io->promptVal('$') ++ " ")
246 }
247
248## Minor Influences
249
250### make, find and xargs
251
252Our design for Ruby-like blocks was influenced by these mini-languages.
253
254### Tcl
255
256YSH uses `proc` and `setvar`, which makes it look something like Tcl:
257
258 proc p(x) {
259 setvar y = x * 2
260 echo $y
261 }
262
263 p 3 # prints 6
264
265But this is mostly superficial: YSH isn't homoiconic like Tcl is, and has a
266detailed syntax. It intentionally avoids dynamic parsing.
267
268However, [Data Definition and Code Generation in Tcl (PDF)][config-tcl] shows
269how Tcl can be used a configuration language:
270
271 change 6/11/2003 {
272 author "Will Duquette"
273 description {
274 Added the SATl component to UCLO.
275 }
276 }
277
278Hay blocks in YSH allow this to be expressed very similarly:
279
280 hay define Change
281
282 Change 6/11/2003 {
283 author = "Will Duquette"
284 description = '''
285 Added the SATl component to UCLO.
286 '''
287 }
288
289
290[config-tcl]: https://trs.jpl.nasa.gov/bitstream/handle/2014/7660/03-1728.pdf
291
292### PHP
293
294PHP has global variables like `_REQUEST` and `_POST`.
295
296YSH has `_error`, `_group()`, `_start()`, etc. These are global variables that
297are "silently" mutated by the interpreter (and functions to access such global
298data).
299
300### Lua
301
302YSH also uses a leading `=` to print expressions in the REPL.
303
304 = 1 + 2
305
306Lua's implementation as a pure ANSI C core without I/O was also influential.
307
308### C
309
310Most of our C-like syntax can be attributed to JavaScript or Python. But the
311`value.Place` type is created with the `&` operator, and should be familiar to
312C users:
313
314 $ echo hi | read --all (&myvar)
315 $ echo "myvar=$myvar"
316 => myvar=hi
317
318So a `value.Place` behaves like a pointer in some ways.
319
320The `&` syntax may also feel familiar to Rust users.
321
322### C++
323
324Using `->` to indicate mutating methods may feel familiar to C++ users:
325
326 call mylist->append(42)
327
328Compared with:
329
330 var x = mystr.trim()
331
332### Swift/Rust
333
334YSH has an explicit range syntax that is inspired by Swift and Rust:
335
336 $ = 3 ..< 5 # => 3, 4
337 $ = 3 ..= 5 # => 3, 4, 5
338
339## Related
340
341- [Novelties in OSH and YSH](novelties.html)
342
343<!--
344
345Config Dialect:
346
347- nginx configs?
348- HCL?
349
350What about JS safe string interpolation?
351
352- r"foo"
353
354LATER:
355
356- R language (probably later, need help): data frames
357 - lazy evaluation like mutate (ms = secs * 100)
358
359Go for type signatures:
360
361 func add(x Int, y Int) Int {
362 return x + y
363 }
364 # what about named return values?
365
366Python/MyPy for types like List[Int], Dict[Str, Str]
367(Swift and Perl 6 also capitalize all types)
368
369Rust:
370
371 enum
372 |x| x+1
373
374Clojure:
375
376\n and \newline for character literals, but YSH uses #'n' and \n
377
378maybe set literals with #{a b c} vs. #{a, b, c}
379
380## Paradigms and Style
381
382Shell is already mix of:
383
384- dataflow: concurrent processes and files, pipelines
385 - instead of Clojure's "functions and data", we have "processes and files".
386 Simple. Functional. Transforming file system trees is a big part of
387 containers.
388- imperative: the original Bourne shell added this.
389 - "functions" are really procedures; return
390 - iteration constructs: while / for / break / continue
391 - conditional constructs: if / case
392
393YSH is:
394
395- getting rid of: ksh. Bourne shell is good; ksh is bad because it adds bad
396 string operators.
397 - `${x%%a}` `${x//}` getting rid of all this crap. Just use functions.
398 - korn shell arrays suck. Replaced with python-like arrays
399- Add Python STRUCTURED DATA.
400 - the problem with PROCESSES AND FILES is that it forces serialization everywhere.
401 - Structured Data in YSH
402- Add **declarative** paradigm to shell.
403 - Package managers like Alpine Linux, Gentoo need declarative formats. So do
404 tools like Docker and Chef.
405- Language-Oriented -- internal DSLs.
406-->