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

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