Differences from Pip Classic
The 2018-10-25 commit of Pip is known as Pip Classic. This is the version of Pip available at Try It Online! If you’re trying to run a Pip program on TIO and something isn’t working the way it should, you might be using a language feature that isn’t in Pip Classic. Here is a catalog of the differences between Pip 1.0 and Pip Classic, plus some tips on how to work around them. (For features added since Pip 1.0, see the What’s New page.)
Note: “lhs” = left-hand side argument of an operator and “rhs” = right-hand side argument (including the single argument of a unary operator).
Flags
- The
-x
flag is not supported. Evaluate the arguments explicitly: useVa
fora
,V*g
forg
, etc.
Syntax
- The Else branch of an If statement begins with
E
, notEL
. - For loops do not support destructuring assignment. Switching to a functional programming approach will usually be shorter anyway:
F[ab]lPaRb'_
->P{aRb'_}MUl
with the appropriate list-formatting flag. - The Swap and Unify statements exist.
- Arbitrary-length variable names starting with
$
are not supported. - There is no block comment syntax.
Data types
- The str/repr of a Block is a stringified Python list representing a parse tree (with the outer
[]
delimiters changed to{}
) rather than a string that evaluates to the same Block. Don’t use the str or repr of a Block for anything except debugging purposes.
Missing operators
- Unary
%
. Mod by 2 explicitly:%a
->a%2
. - Unary
**
. Raise 2 to the power explicitly:**a
->2**a
. ::
(binary). Use the swap command instead:a::b
->Sab
.- Unary
<>
. Group into size-2 chunks explicitly:<>a
->a<>2
. \?
(ternary),\|
and\&
(binary), and\!
(unary). Use a curly-brace function instead of a lambda, or look for another way to express the formula:_\|'x
->{a|'x}
;\!_
->_=0
if the argument is guaranteed to be a number.AD
(binary). Subtract and take the absolute value instead:aADb
->AB(a-b)
.D
(unary). Use--
instead, but note the slight difference in precedence:Da
->--a
;Da@<2
->--(a@<2)
.DB
(unary). Multiply by 2 explicitly:DBa
->a*2
.E
(unary and binary). Use**
instead:Ea
->2**a
;aEb
->a**b
.EE
(unary and binary). Use the full formula instead:EEa
->10**a
;aEEb
->a*10**b
.FD
(unary and binary). UseFB
or roll your own base-conversion:aFDb
->$+a*b**RV,#a
, or(Ja)FBb
ifb
is 36 or less and all digits are less than 10.- Unary
FI
. Filter by the identity function instead:FIa
->_FIa
. H
(unary and binary). Use@<
instead, but note the difference in precedence:Ha
->@<a
;aHb
->a@<b
;a.bHc-2
->(a.b)@<(c-2)
.HV
(unary). Divide by 2 explicitly:HVa
->a//2
, ora/2
ifa
is known to be an even number.OG
(unary and binary). Use one ofZG
,MC
, orCG
instead:OGa
->1+ZGa
or1MCa
;aOGb
->1+(aZGb)
or1MMaCGb
.RE
(unary). Use an explicit function call instead:REa
->(fa)
.- Unary
R
. UseRV
instead:Ra
->RVa
. S
(unary and binary). Use@>
instead (with a negated second argument if binary), but note the difference in precedence:Sa
->@>a
;aSb
->a@>-b
;a.bSc-2
->(a.b)@>(2-c)
.SQ
(unary). Multiply the number by itself or use**
instead:SQa
->a*a
ora**2
.TD
(unary and binary). UseTB
or roll your own base-conversion:aTDb
->^aTBb
ifb
is 10 or less.U
(unary). Use++
instead, but note the slight difference in precedence:Ua
->++a
;Ua@<2
->++(a@<2)
.
Operators with different behavior
- Unary
#
,A
,AB
,C
,FB
, andSG
have higher precedence than binary@
,@>
, and@<
. Use parentheses or another precedence-manipulation strategy as needed:A*s@<3
->A*(s@<3)
orA*Ys@<3
;#l@1
->#(l1)
:
does not support destructuring assignment. For simple cases, use theU
statement:[xyz]:a
->UxyzWa
. More-complex cases may need to use a series of assignments and/or unifications:C:[xyz]
->C:xC:yC:z
;[[wx][yz]]:a
->UwxW@aUyzWa@1
.- Numeric and string equality operators (
=
,<=
,>=
,Q
,LE
, andGE
) always return falsey when their arguments are not comparable, rather than returning truthy if the arguments are identical. (In particular, nil is not equal to nil, and a Pattern is not equal to itself under numeric comparison.) If this becomes a problem, you can explicitly check for exact equality first:a<=b
->a==b|a<=b
. <>
does not work with a negative rhs. To group from right to left, useRV
twice:a<>-4
->RV*(RVa<>4)
.<>
does not accept a List or Range as rhs. To return a list of different groupings, map a lambda function:a<>[2 4]
->a<>_M[2 4]
.MC
does not accept a height/width List as rhs. Use binaryCG
withMM
instead, but note thatMM
does not unpack the coordinate pairs:_.s.BMC[ab]
->_@0.s._@1MMaCGb
.N
andNI
do not accept a List/Range lhs with a Scalar rhs. Map a lambda function instead:[1 2 4]Na
->_NaM[1 2 4]
.
Missing variables
(These still act as variables, but their initial values are nil rather than the useful values they have in current Pip.)
p
: use"()"
instead.G
: use{g}
instead, or rework your lambda function using_
andB
if possible:2*$+G
->{2*$+g}
or2*$+{g}
or, if you know there will always be two arguments,2*_+2*B
.VD
andVN
: not supported, but not particularly useful for golf anyway.
Bugs
- Using
<>
with a rhs of 0 or a negative number results in an infinite loop. Only use<>
with positive rhs. See above for how to group from right to left. - A Scalar with leading whitespace in a numeric context evaluates to
0
, rather than ignoring the whitespace. If leading whitespace is a possibility, strip it explicitly using|>
. - A non-integer rhs to
\,
crashes the interpreter. Only use\,
with integer rhs. If a non-integer rhs is a possibility, int-divide it by 1 to truncate it to an integer. - Using
A
with a Scalar rhs matching the regex0+(\.0+)?
results in nil rather than 48. Concatenating space or some other character to the end of the Scalar is one possible workaround. <
returns 1 when given two Lists that are equal. Swap the arguments and use>
instead.#
and the length-comparison operators crash the interpreter when given infinite Ranges. Try to avoid taking the length of infinite Ranges. If you need to test the upper bound of a Range, useMX
.- Iterating over an infinite Range with a lower bound of nil crashes the interpreter. Use a lower bound of 0 instead.
- Indexing into an empty iterable and then attempting to assign a value to that expression crashes the interpreter. Make sure iterables are nonempty before attempting to assign to their items.
- Indexing into a variable whose value is a Range gives nil. Convert to a List first (e.g. by multiplying by 1) or use math instead of indexing into a Range.
- Applying an operator with the
*
meta-operator to a Block crashes the interpreter. Use a curly-brace delimited function instead of a lambda function, or find a way not to use the meta-operator:A*_
->{A*a}
or possiblyA^_
. - Weaving a List containing nil crashes the interpreter. If this ever becomes an issue, one potential workaround is to filter the List before weaving it:
WVl
->WV(#_FIl)
.