| 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 |
|