| 1 | ---
 | 
| 2 | ---
 | 
| 3 | 
 | 
| 4 | YSH Expressions vs. Python
 | 
| 5 | ==========================
 | 
| 6 | 
 | 
| 7 | The [YSH]($xref) expression language borrows heavily from Python.  In fact, it
 | 
| 8 | literally started with Python's `Grammar/Grammar` file.
 | 
| 9 | 
 | 
| 10 | This doc describes the differences, which may help Python users learn YSH.
 | 
| 11 | 
 | 
| 12 | If you don't know Python, [A Tour of YSH](ysh-tour.html) explains the language
 | 
| 13 | from the clean-slate perspective.
 | 
| 14 | 
 | 
| 15 | (TODO: A separate doc could compare commands/statements like `for` and `if`.)
 | 
| 16 | 
 | 
| 17 | <div id="toc">
 | 
| 18 | </div>
 | 
| 19 | 
 | 
| 20 | ## Background
 | 
| 21 | 
 | 
| 22 | YSH has dynamic types, much like Python.  These are the main **data** types:
 | 
| 23 | 
 | 
| 24 |     Null Bool Int Float List Dict
 | 
| 25 | 
 | 
| 26 | Quick example:
 | 
| 27 | 
 | 
| 28 |     var x = null
 | 
| 29 |     var y = f(true, 42, 3.14)
 | 
| 30 |     var z = [5, 6, {name: 'bob'}]
 | 
| 31 | 
 | 
| 32 | ## Literals
 | 
| 33 | 
 | 
| 34 | Every data type can be written as a literal.  Literals generally look like
 | 
| 35 | Python, so this section describes what's the same, and what's changed /  added
 | 
| 36 | / and removed.
 | 
| 37 | 
 | 
| 38 | ### Like Python: numbers and lists
 | 
| 39 | 
 | 
| 40 | - Integers: `123`, `1_000_000`, `0b1100_0010`, `0o755`, `0xff`
 | 
| 41 | - Floats: `1.023e6`
 | 
| 42 | - Lists: `['pea', 'nut']`
 | 
| 43 |   - TODO: we want Python-like list comprehensions
 | 
| 44 | 
 | 
| 45 | ### Changed: booleans, strings, dicts
 | 
| 46 | 
 | 
| 47 | - Atoms are `true`, `false`, and `null` (like JavaScript) rather than `True`,
 | 
| 48 |   `False`, and `None` (like Python).
 | 
| 49 |   - In YSH, we use capital letters for types like `Int`.
 | 
| 50 | 
 | 
| 51 | - String literals are like **shell** string literals, not like Python.
 | 
| 52 |   - Double Quoted: `"hello $name"`
 | 
| 53 |   - Single quoted: `r'c:\Program Files\'` 
 | 
| 54 |   - C-style: `$'line\n'` (TODO: change to J8 Notation)
 | 
| 55 |     - Unicode literals are `\u{3bc}` instead of `\u03bc` and `\U000003bc`
 | 
| 56 | 
 | 
| 57 | - Dicts use **JavaScript** syntax, not Python syntax.
 | 
| 58 |   - Unquoted keys: `{age: 42}`
 | 
| 59 |   - Bracketed keys: `{[myvar + 1]: 'value'}`
 | 
| 60 |   - "Punning": `{age}`
 | 
| 61 | 
 | 
| 62 | ### Added
 | 
| 63 | 
 | 
| 64 | - Shell-like list literals: `:| pea nut |` is equivalent to `['pea', 'nut']`
 | 
| 65 | 
 | 
| 66 | - "Quotation" types for unevaluated code:
 | 
| 67 |   - Command / block `^(ls | wc -l)`
 | 
| 68 |   - Unevaluated expression `^[1 + a[i] + f(x)]`
 | 
| 69 | 
 | 
| 70 | - Units on number constants like `100 MiB` (reserved, not implemented)
 | 
| 71 | 
 | 
| 72 | <!--
 | 
| 73 | - Character literals are **integers**
 | 
| 74 |   - Unicode `\u{03bc}`
 | 
| 75 |   - Backslash: `\n`  `\\`  `\'`
 | 
| 76 |   - Pound `#'a'`
 | 
| 77 | - `:symbol` (could be used as interned strings)
 | 
| 78 | -->
 | 
| 79 | 
 | 
| 80 | ### Omitted
 | 
| 81 | 
 | 
| 82 | - YSH has no tuples, only lists.
 | 
| 83 | - No lambdas (function literals returning an expression)
 | 
| 84 | - No closures, or scope declarations like `global` and `nonlocal`.  (We would
 | 
| 85 |   prefer objects over closures.)
 | 
| 86 | - No iterators.
 | 
| 87 |   - Instead we have for loop that works on lists and dicts.
 | 
| 88 |   - It flexibly accepts up to 3 loop variables, taking the place of Python's
 | 
| 89 |     `enumerate()`, `keys()`, `values()`, and `items()`.
 | 
| 90 | 
 | 
| 91 | ## Operators
 | 
| 92 | 
 | 
| 93 | Like literals, YSH operators resemble Python operators.  The expression `42 +
 | 
| 94 | a[i]` means the same thing in both languages.
 | 
| 95 | 
 | 
| 96 | This section describes what's the same, and what's changed / added / removed.
 | 
| 97 | 
 | 
| 98 | ### Note: YSH Does Less Operator Overloading
 | 
| 99 | 
 | 
| 100 | YSH doesn't overload operators as much because it often does automatic
 | 
| 101 | `Str` ↔ `Int` conversions (like Awk):
 | 
| 102 | 
 | 
| 103 | - `a + b` is for addition, while `a ++ b` is for concatenation.
 | 
| 104 | 
 | 
| 105 | - `a < b` does numeric comparison, not lexicographical comparison of strings.
 | 
| 106 |   - (We should add `strcmp()` for strings.)
 | 
| 107 | 
 | 
| 108 | ### Like Python
 | 
| 109 | 
 | 
| 110 | - Arithmetic `+ - * /` and comparison `< > <= =>`.  They also convert strings
 | 
| 111 |   to integers or floats.  Examples:
 | 
| 112 |   - `'22' < '3'` is true because `22 < 3` is true.
 | 
| 113 |   - `'3.1' <= '3.14'` is true because `3.1 <= 3.14` is true.
 | 
| 114 | 
 | 
| 115 | - Integer arithmetic: `//` integer division, `%` modulus, `**` exponentiation.
 | 
| 116 |   - They also convert strings to integers (but not floats).
 | 
| 117 | 
 | 
| 118 | - Bitwise `& | ~ ^ << >>`
 | 
| 119 | 
 | 
| 120 | - Logical `and or not`
 | 
| 121 | 
 | 
| 122 | - Ternary `0 if cond else 1`
 | 
| 123 | 
 | 
| 124 | - Slicing: `s[i:j]` evaluates to a string
 | 
| 125 | 
 | 
| 126 | - Membership `in`, `not in`
 | 
| 127 | 
 | 
| 128 | - Identity `is`, `is not`
 | 
| 129 | 
 | 
| 130 | - Function Call: `f(x, y)`
 | 
| 131 | 
 | 
| 132 | ### Changed
 | 
| 133 | 
 | 
| 134 | - Equality is `=== !==`, because we also have `~==`.
 | 
| 135 | - String Concatenation is `++`, not `+`.  Again, `+` is always addition.
 | 
| 136 | - Splat operator is `...` not `*`: `f(...myargs)`.
 | 
| 137 | 
 | 
| 138 | ### Added
 | 
| 139 | 
 | 
| 140 | - Eggex match `s ~ /d+/`
 | 
| 141 | - Glob match `s ~~ '*.py'`
 | 
| 142 | - Approximate Equality `42 ~== '42'`
 | 
| 143 | - YSH sigils: `$` and `@`
 | 
| 144 | - `mydict.key` as an alias for `mydict['key']`
 | 
| 145 | 
 | 
| 146 | ### Omitted
 | 
| 147 | 
 | 
| 148 | - No string formatting with `%`.  Use `${x %.3f}` instead. (unimplemented)
 | 
| 149 | - No `@` for matrix multiply.
 | 
| 150 | - I removed slice step syntax `1:5:2` because `0::2` could conflict with
 | 
| 151 |   `module::name` (could be restored).
 | 
| 152 | 
 | 
| 153 | ## Syntax Compared With JavaScript
 | 
| 154 | 
 | 
| 155 | This section may be useful if yo know JavaScript.
 | 
| 156 | 
 | 
| 157 | - YSH uses `===` and `~==` for exact and type-converting equality, while JS
 | 
| 158 |   uses `===` and `==`.
 | 
| 159 | 
 | 
| 160 | - Expressions are more like Python:
 | 
| 161 |   - YSH expressions use `and or not` while JS uses `&& || !`.  In shell, `&& ||
 | 
| 162 |     !` are already used in the command language (but they're somewhat less
 | 
| 163 |     important than in YSH).
 | 
| 164 |   - The YSH ternary operator is `0 if cond else 1`, while in JS it's `cond ? 0 :
 | 
| 165 |     1`.
 | 
| 166 |   - Operator precedence rules are slightly different, but still C-like.  They
 | 
| 167 |     follow Python's grammar.
 | 
| 168 | 
 | 
| 169 | - Same differences as above, versus Python:
 | 
| 170 |   - `s ++ t` for string concatenation rather than `s + t`
 | 
| 171 |   - Shell string literals rather than JS string literals
 | 
| 172 | 
 | 
| 173 | ## Semantics Compared
 | 
| 174 | 
 | 
| 175 | The runtime behavior of YSH is also similar to Python and JavaScript.
 | 
| 176 | 
 | 
| 177 | ### Versus Python
 | 
| 178 | 
 | 
| 179 | - `Bool` and `Int` are totally separate types.  YSH is like JavaScript, where
 | 
| 180 |   they aren't equal: `true !== 1`.  In Python, they are equal: `True == 1`.
 | 
| 181 | 
 | 
| 182 | - Strings are bytes, which may UTF-8 encoded, like Go.  (In Python 3, strings
 | 
| 183 |   are sequences of code points, which are roughly integers up to
 | 
| 184 |   2<sup>21</sup>.)
 | 
| 185 | 
 | 
| 186 | - We avoid operators that cause "accidentally quadratic" behavior.
 | 
| 187 |   - No `in` on `List`, since that's a linear search.  Only `in` on `Dict`.
 | 
| 188 |   - The're not `++=` operator on strings.
 | 
| 189 | 
 | 
| 190 | <!-- TODO: "N ways to concat strings " -->
 | 
| 191 | 
 | 
| 192 | ### Versus JavaScript
 | 
| 193 | 
 | 
| 194 | - Strings are bytes, which may UTF-8 encoded, like Go.  (In 
 | 
| 195 |   JavaScript are sequences of UTF-16 code units, which are roughly integers up
 | 
| 196 |   to 2<sup>16</sup>.)
 | 
| 197 | - Undefined variables result in a fatal error like Python, not a silently
 | 
| 198 |   propagating `undefined` like JavaScript.
 | 
| 199 | 
 | 
| 200 | 
 |