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

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