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

373 lines, 249 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### JavaScript
93
94YSH uses JavaScript's dict literals:
95
96 var d1 = {name: 'Alice', age: 10} # Keys aren't quoted
97
98 var d2 = {[mystr]: 'value'} # Key expressions in []
99
100 var name = 'Bob'
101 var age = 15
102 var d3 = {name, age} # Omitted values taken from surrounding scope
103
104Blocks use curly braces, so most code resembles C / Java / JavaScript:
105
106 if (x > 0) {
107 echo 'positive'
108 } else {
109 echo 'zero or negative'
110 }
111
112 var i = 5
113 while (i > 0) {
114 echo $i
115 setvar i -= 1
116 }
117
118### Ruby
119
120YSH has Ruby-like blocks:
121
122 cd /tmp {
123 echo $PWD # prints /tmp
124 }
125 echo $PWD
126
127### Perl
128
129The `@` character comes from Perl (and PowerShell):
130
131 var myarray = :| one two three |
132 echo @myarray # @ is the "splice" operator
133
134 echo @[arrayfunc(x, y)]
135
136 for i in @(seq 3) { # split command sub
137 echo $i
138 }
139
140<!--
141The unbuffered `for` loop is similar to Perl's `while (<>) { ...`:
142
143 for line in <> {
144 echo $line
145 }
146-->
147
148Perl can be viewed as a mixture of shell, awk, and sed. YSH is a similar
149agglomeration of languages, but it's statically parsed.
150
151### Julia
152
153The semicolon in `proc` and `func` definitions comes from Julia:
154
155 func f(x, y; invert=false) {
156 if (invert) {
157 return (-x - y)
158 } else {
159 return (x + y)
160 }
161 }
162
163Multiline strings in YSH strip leading whitespace, similar to Julia:
164
165 proc p {
166 # Because leading and trailing space are stripped, this is 2 lines long
167 var foods = '''
168 peanut
169 coconut
170 '''
171 }
172
173
174(Julia has something like blocks too.)
175
176### Go
177
178Like Go, Oils is UTF-8-centric. (Go blog: [Strings, bytes, runes and
179characters in Go](https://go.dev/blog/strings).)
180
181The design of for loops is roughly influenced by Go:
182
183 for i, item in (mylist) { # ask for index and value
184 echo "$i $item"
185 }
186
187 for i, k, v in (mydict) { # ask for index, key, and value
188 echo "$i $k $v"
189 }
190
191### Awk
192
193YSH gets its regex match operator from Awk:
194
195 if (mystr ~ /digit+/) {
196 echo 'Number'
197 }
198
199(We don't use Perl's `=~` operator.)
200
201### Lisp
202
203YSH has "quotation types" that represent unevaluated code. Like Lisp, they
204give you control over evaluation:
205
206 var my_cmd = ^(ls /tmp | wc -l)
207 eval (my_cmd)
208
209 var my_expr = ^[42 + a[i]]
210 var v = evalExpr(my_expr)
211
212 var my_template = ^"hi $name" # unimplemented
213
214### Haskell
215
216YSH also uses `++` to concatenate strings and lists:
217
218 var mystr = a ++ b
219 var mystr = "$a$b" # very similar
220
221 var mylist = c ++ d
222 var mylist = :| @c @d | # also converts every element to a string
223
224YSH has a `value.IO` type that makes functions pure:
225
226 func renderPrompt(io) {
227 return (io->promptVal('$') ++ " ")
228 }
229
230## Minor Influences
231
232### make, find and xargs
233
234Our design for Ruby-like blocks was influenced by these mini-languages.
235
236### Tcl
237
238YSH uses `proc` and `setvar`, which makes it look something like Tcl:
239
240 proc p(x) {
241 setvar y = x * 2
242 echo $y
243 }
244
245 p 3 # prints 6
246
247But this is mostly superficial: YSH isn't homoiconic like Tcl is, and has a
248detailed syntax. It intentionally avoids dynamic parsing.
249
250However, [Data Definition and Code Generation in Tcl (PDF)][config-tcl] shows
251how Tcl can be used a configuration language:
252
253 change 6/11/2003 {
254 author "Will Duquette"
255 description {
256 Added the SATl component to UCLO.
257 }
258 }
259
260Hay blocks in YSH allow this to be expressed very similarly:
261
262 hay define Change
263
264 Change 6/11/2003 {
265 author = "Will Duquette"
266 description = '''
267 Added the SATl component to UCLO.
268 '''
269 }
270
271
272[config-tcl]: https://trs.jpl.nasa.gov/bitstream/handle/2014/7660/03-1728.pdf
273
274### PHP
275
276PHP has global variables like `_REQUEST` and `_POST`.
277
278YSH has `_error`, `_group()`, `_start()`, etc. These are global variables that
279are "silently" mutated by the interpreter (and functions to access such global
280data).
281
282### Lua
283
284YSH also uses a leading `=` to print expressions in the REPL.
285
286 = 1 + 2
287
288Lua's implementation as a pure ANSI C core without I/O was also influential.
289
290### C
291
292Most of our C-like syntax can be attributed to JavaScript or Python. But the
293`value.Place` type is created with the `&` operator, and should be familiar to
294C users:
295
296 $ echo hi | read --all (&myvar)
297 $ echo "myvar=$myvar"
298 => myvar=hi
299
300So a `value.Place` behaves like a pointer in some ways.
301
302The `&` syntax may also feel familiar to Rust users.
303
304## Related
305
306- [Novelties in OSH and YSH](novelties.html)
307
308<!--
309
310Config Dialect:
311
312- nginx configs?
313- HCL?
314
315What about JS safe string interpolation?
316
317- r"foo"
318
319LATER:
320
321- R language (probably later, need help): data frames
322 - lazy evaluation like mutate (ms = secs * 100)
323
324Go for type signatures:
325
326 func add(x Int, y Int) Int {
327 return x + y
328 }
329 # what about named return values?
330
331and MyPy for types like List[Int], Dict[Str, Str]
332
333(Swift and Perl 6 also capitalize all types)
334
335Rust:
336
337 0..n and 1..=n ?
338 enum
339 |x| x+1
340
341Clojure:
342
343\n and \newline for character literals, but YSH uses #'n' and \n
344
345maybe set literals with #{a b c} vs. #{a, b, c}
346
347## Paradigms and Style
348
349Shell is already mix of:
350
351- dataflow: concurrent processes and files, pipelines
352 - instead of Clojure's "functions and data", we have "processes and files".
353 Simple. Functional. Transforming file system trees is a big part of
354 containers.
355- imperative: the original Bourne shell added this.
356 - "functions" are really procedures; return
357 - iteration constructs: while / for / break / continue
358 - conditional constructs: if / case
359
360YSH is:
361
362- getting rid of: ksh. Bourne shell is good; ksh is bad because it adds bad
363 string operators.
364 - `${x%%a}` `${x//}` getting rid of all this crap. Just use functions.
365 - korn shell arrays suck. Replaced with python-like arrays
366- Add Python STRUCTURED DATA.
367 - the problem with PROCESSES AND FILES is that it forces serialization everywhere.
368 - Structured Data in YSH
369- Add **declarative** paradigm to shell.
370 - Package managers like Alpine Linux, Gentoo need declarative formats. So do
371 tools like Docker and Chef.
372- Language-Oriented -- internal DSLs.
373-->