A Dylan Primer for Python Programmers

Note

If one column contains N/A, then that language has no corresponding direct way to express what is in the other column.

Literals

Python

Dylan

True
#t
False
#f
23
23
0b1011
#b1011
0o644
#o644
0x2A5F
#x2A5F
6.02e+23
6.02e+23 // double float
6.02s+23 // single float
6.02d+23 // double float

N/A

No individual characters other than integer character codes

'a'
'\n'
'Hello'
'Hello\n'
"Hello"
"Hello\n"
s = '''Hi, from
python'''


# No Rectangle rule
s = '''
    Hi, from
    Python
    '''
let s = """
Hi, from
Dylan
""";
// Rectangle rule support
let s = """
        Hi, from
        Dylan
        """;

N/A

Not real symbols but strings are interned

#"apple"
apple:

N/A

No symbols

#"two words"
(1, 'a', 'dog')

N/A

No tuples (see multiple values)

[5, 10, 15]
#[5, 10, 15]

Syntax

Note

In Dylan, any words after an end (e.g. end method) are optional but, if present, must match the corresponding “begin” word.

Python

Dylan

var = exp



VAR = exp # Convention
let var = exp;
var := exp;
define variable var = exp;
define variable var :: type = exp;
define constant var = exp;
f(x, y, z)
f(x, y, z)
1
2
3
begin 1; 2; 3; end
begin 1; 2; 3 end
lambda x, y, *z:
  print('hello')
  return f(x, y, z)
method (x, y, #rest z)
  format-out("hello");
  f(x, y, z)
end method
x, y = exp
let (x, y) = exp
x, y = (5, 6)
f(x, y)
let (x, y) = values(5, 6);
f(x, y)
def foo():
  def f(x):
    f-body

  def g(y, z):
    g-body

  body
define function foo ()
  local method f (x)
          f-body
        end,
        method g (y, z)
          g-body
        end;
  body
end;
if test:
  then1
  then2
else:
  else1
  else2
if (test)
  then1;
  then2;
else
  else1;
  else2;
end if
a and b and c
a & b & c
a or b or c
a | b | c
if test1:
  result1
elif test2:
  result2
else:
  result
case
  test1 => result1;
  test2 => result2;
  otherwise => result
end case
if exp in (1, 2):
  result1
elif exp in ('a', 'b'):
  result2
else:
  result
select (exp)
  1, 2 => result1;
  'a', 'b' => result2;
  otherwise => result
end select
c = comparison-func(exp)
if c == 'foo':
  result1
elif c == 'bar':
  result2
else:
  result
select (exp by comparison-func)
  "foo" => result1;
  "bar" => result2;
  otherwise => result
end select
var1 = init1
var2 = init2
while not test:
  body
  var1 = step1
  var2 = step2
return var1
for (var1 = init1 then step1,
     var2 = init2 then step2,
     until: test)
  body
finally var1
end for

Predefined functions

Boolean functions

Python

Dylan

not obj
~ obj
~obj
isinstance(obj, bool)
instance?(obj, <boolean>)

Equivalence predicates

Python

Dylan

x == y
x = y
x is y
x == y

Symbols

Python

Dylan

N/A

instance?(obj, <symbol>)

N/A

as(<string>, sym)
as(<symbol>, str)

Numerical operations

Python

Dylan

isinstance(obj,
  (int, float, complex))
instance?(obj, <number>)
isinstance(obj, complex)
instance?(obj, <complex>)
isinstance(obj,
  (int, float))
instance?(obj, <real>)
isinstance(obj, int) or
  (isinstance(obj, float) and
    obj == int(obj))
instance?(obj, <rational>)
isinstance(obj, int)
instance?(obj, <integer>)
integral?(num)
n1 == n2
n1 == n2
n1 < n2
n1 < n2
n1 > n2
n1 > n2
n1 <= n2
n1 <= n2
n1 >= n2
n1 >= n2
n == 0
0 == 0.0 # True
zero?(n)
0 == 0.0 // #f
n > 0
positive?(n)
n < 0
negative?(n)
i % 2 != 0
odd?(i)
i % 2 == 0
even?(i)
1 + 2 + 3
1 + 2 + 3
1 * 2 * 3
1 * 2 * 3
5 - 3
5 - 3
1 / 2 # 0.5
1 / 2           // error
1.0 / 2         // 0.5
truncate/(1, 2) // 0
ceiling/(1, 2)  // 1
floor/(1,2)     // 0
-x
- x
-x
2 ** 16
2 ^ 16
max(1, 2, 3)
max([1, 2, 3])
max(1, 2, 3)
apply(max, #(1, 2, 3))
5 % 2
remainder(5, 2)

Characters

Python

Dylan

isinstance(obj, str) and
  len(obj) == 1
instance?(obj, <character>)
char1 == char2
char1 == char2
char1 < char2
char1 < char2
char1 > char2
char1 > char2
char1 <= char2
char1 <= char2
char1 >= char2
char1 >= char2
ord(char)
as(<integer>, char)
chr(n)
as(<character>, n)
char.upper()
as-uppercase(char)
char.lower()
as-lowercase(char)

Strings

Python

Dylan

isinstance(obj, str)
instance?(obj, <string>)
'x' * k
make(<string>, size: k, fill: char)
"".join('a', 'b', 'c'])
as(<string>, #['a', 'b', 'c'])
len(str)
size(str)
str.size
str[k]
element(str, k)
str[k]
# Strings are immutable
element-setter(char, str, k)
str[k] := char
str1 == str2
str1 = str2
str1 < str2
str1 < str2
str[start:end]
copy-sequence(str, start: start, end: end)
str1 + str2
concatenate(str1, str2)
list(str)
as(<list>, str)
list(str)
as(<string>, chars)
copy(str)
shallow-copy(str)
copy-sequence(str)
# Strings are immutable
fill!(str, char)

Vectors

Python

Dylan

isinstance(obj, list)
instance?(obj, <vector>)
[fill] * k
make(<vector>, size: k, fill: fill)
[obj, ...]
vector(obj, ...)
len(vec)
size(vec)
vec.size
vec[k]
element(vec, k)
vec[k]
vec[k] = obj
element-setter(obj, vec, k)
vec[k] := obj
list(vec)
as(<list>, vec)
# Uses lists for both
list(list)
as(<vector>, list)
for i in range(len(vec)):
  vec[i] = obj
fill!(vec, obj)

Control Features

Python

Dylan

callable(obj)
instance?(obj, <function>)
proc(arg1, arg2, *args)
apply(proc, arg1, arg2, args)
map(proc, list1, list2, ...)
# returns iterator in
# Python 3
map(proc, list1, list2, ...)
map(proc, vec1, vec2, ...)
map(proc, vec1, vec2, ...)
map(proc, str1, str2)
map(proc, str1, str2)
for a,b in zip(list1, list2):
  proc(a, b)
do(proc, list1, list2)

Continuations

Python doesn’t have first-class continuations like Scheme’s call/cc, and Dylan’s block syntax is more like structured exception handling or generators.

Here are approximate equivalents:

Python

Dylan

def example():
  try:
    body()
  except Error as e:
    handle_error()
  finally:
    cleanup_stuff()
block (k)
  body
exception (e :: <error>)
  handle-error()
cleanup
  cleanup-stuff
end block

N/A

define function top ()
  block (exit-block)
    bar(exit-block);
    format-out("You won't see this.\n");
  end;
  format-out("You WILL see this.\n");
end;

define function bar (thunk)
  thunk()
end;

top();

Keyword arguments

Python

Dylan

def wrapper_fn (a, b, c, **keys):
  do_stuff(a, b, c)
return wrapped_fn(**keys)

def wrapped_fn (one = 1, two = 2, three = 3):
  return [one, two, three]
define method wrapper-fn (a, b, c, #rest keys)
  do-stuff(a, b, c);
  apply(wrapped-fn, keys)
end;

define method wrapped-fn
  (#key one = 1, two = 2, three = 3)
  list(one, two, three)
end;

Python collects any number of keyword arguments into a dictionary. In Dylan, #rest keys collects the remaining arguments, not into a dictionary, but into a vector (like a property list or plist): alternating symbol-value pairs.

Loops

for

Python

Dylan

words = ['one', 'two']
for w in words:
  print(w, len(w))
let words = #("one", "two")
for (w in words)
  format-out("%s %d\n", w, w.size)
end;

N/A Tail recursion

iterate loop (words = #("one", "two"))
  if (~empty?(words))
    let word = head(words);
    format-out("%s %d\n", word, word.size);
    loop(tail(words))
  end
end

while

Python

Dylan

a, b = 0, 1
while (a < 10):
  print(a)
  a, b = b, a+b
let (a, b) = values(0, 1);
while (a < 10)
  format-out("%d\n", a);
  let temp = a;
  a := b; b := temp + b;
end

N/A Tail recursion

iterate loop (a = 0, b = 1)
  if (a < 10)
     format-out("%d\n", a);
     loop(b, a + b)
  end
end

until

Python

Dylan

N/A

let count = 5;
until (count = 0)
  format-out("Count is %d\n", count);
  count := count - 1;
end;

N/A

// tail recursion
iterate loop (count = 5)
  if (count > 0)
    format-out("Count is %d\n", count);
    loop(count - 1)
  end
end

break

Python

Dylan

for i in range(10):
  if i == 5:
    break
  print(i)
block(break)
  for (i from 0 below 10)
    if (i = 5) break() end;
    format-out("%d\n", i);
  end;
end

continue

Python

Dylan

for i in range(5):
  if i == 2:
    continue
  print(i)
for (i from 0 below 5)
  block(continue)
    if (i = 2) continue() end;
    format-out("%d\n", i);
  end;
end

pass

Python

Dylan

if some_condition:
  pass
if (some-condition)
  // do nothing
end

match

Python

Dylan

def http_error(status):
  match status:
    case 400:
      return "Bad request"
    case 404:
      return "Not found"
    case _:
      return "Something went wrong"
define function http-error(status)=>(msg)
  select (status)
    400 => "Bad request";
    404 => "Not found";
    otherwise => "Something went wrong";
  end
end

Python

Dylan

# point is an (x, y) tuple
def say(point):
  match point:
    case (0, 0):
      print("Origin")
    case (0, y):
      print(f"Y={y}")
    case (x, 0):
      print(f"X={x}")
    case (x, y):
      print(f"X={x}, Y={y}")
    case _:
      raise ValueError("Not a point")

Dylan has no built-in pattern matching but match can be implemented in a library as a macro.