The document discusses metaclasses and bytecode in Python from the perspective of a Smalltalk user. Smalltalk influenced Python's use of bytecode, though Python's metaclasses differ from Smalltalk. Metaclasses in Smalltalk determine the class of a class, with every class being an instance of its metaclass. In Python, the default metaclass is type, but some standard classes use non-type metaclasses defined in the abc module. The document also provides an overview of Smalltalk bytecode categories and examples, and compares it to the Python bytecode generated for simple methods.
A peek into Python's Metaclass and Bytecode from a Smalltalk User
1. A Peek into Python’s
Metaclass and Bytecode
as a Smalltalk User
Koan-Sin Tan
freedom_at_computer.org
COSCUP 2015, Taipei
2. why this topic
• ‘I was only vaguely aware of Smalltalk at the time; I remember being surprised
by its use of metaclasses (which is quite different from that in Python or
Ruby!) when I read about them much later. Smalltalk's bytecode was a bigger
influence of Python's bytecode though. I'd read about it in a book by Adele
Goldberg and others, I believe "Smalltalk-80: The Language and its
Implementation”’ [1]
• And, I had a talk comparing Ruby’s metaclass and byte code to Smalltalk’s in
the end of 2012 [2]
• google “smalltalk and ruby bytecode”
[1] http://python-history.blogspot.com/2013/10/origin-of-metaclasses-in-
python.html
[2] http://www.slideshare.net/kstan2/smalltalk-and-ruby-20121208-15542185
3. what won’t be discussed
• anything beyond simple metaclass and bytecode
comparisons
• So, no inline cache if you was in the SpiderMonkey talk
yesterday. Yes, I know inline cache was for Smalltalk-80. If
you want to know how inline cache is used in Smalltalk,
read an excellent article [1]
• And no other stuff in object model (whatever object model
means to you)
[1] http://www.mirandabanda.org/cogblog/2011/03/01/build-
me-a-jit-as-fast-as-you-can/
5. who am I
• Learnt to write program on MPF-II
• Used to be a programming language junkie
• Learnt a bit Smalltalk during early '90s, use it on
and off
• Recent interest in ST-80 because of Scratch and
BYOB/SNAP
• Knew little about Python
8. Scratch was written in Smalltalk
8
http://news.softpedia.com/images/reviews/large/
Scratch_Large_001.png
9. What I knew about python
• It’s a popular scripting language
• My classmate told me about Python in ’94 or ’95
• IPython notebook: using python and R to share
notes
• And of course, Python is more than Smalltalk-80
11. Quick Overview of ST-80
• Object-Oriented
Programming
• OO GUI environment,
IDE
• stack VM, bytecode
• Lambda, functional
language, block
• Message passing
• Design Pattern:
• if you read the GoF
book, you ran into
lots of Smalltalk
patterns before
• Learning/educational
• Logo and the dream
of Dynabook
13. Metaclass in ST-80
• From "purple book", Chap 16
1. Every class is ultimately a subclass of class Object, except for Object itself, which
has no superclass. In particular, Class is a subclass of ClassDescription, which is
a subclass of Behavior which is a subclass of Object
2. Every object is an instance of a class
3. Every class is an instance of a metaclass
4. All metaclasses are subclasses of Class
5. Every metaclass is an instance of Metaclass
6. The method of Class and it superclasses support the behavior common to all
objects that are classes
7. The methods of instances of Metaclass add the behavior specific to particular
classes
15. • 10 factorial class allSuperclasses --> an
OrderedCollection(Integer Number Magnitude
Object ProtoObject)
16. Python int
print(type(1))
<class 'int'>
print(type(1).__base__)
<class 'object'>
print(type(1).__base__.__base__)
None
print(type(1).__mro__)
(<class 'int'>, <class ‘object'>)
• So int, then object, no
hierarchy for numbers. How
about container types, e.g.,
set and dict? NO!
• Fortunately, there is another
path since python3000(?)
• There is PEP 3119 “Abstract Base
Classes” (ABC) and its companion
PEP 3141. So, there are ABCs for
numbers in module numbers and
collections module collections
numbers.Integral.__base__
<class 'numbers.Rational'>
numbers.Integral.__base__.__base__
<class 'numbers.Real'>
numbers.Integral.__base__.__base__.__base__
<class 'numbers.Complex'>
numbers.Integral.__base__.__base__.__base__.__base__
<class 'numbers.Number'>
numbers.Integral.__base__.__base__.__base__.__base__.__
base__
<class ‘object'>
numbers.Integral.__mro__
(<class 'numbers.Integral'>, <class
'numbers.Rational'>, <class 'numbers.Real'>, <class
'numbers.Complex'>, <class 'numbers.Number'>, <class
'object'>)
https://docs.python.org/3/reference/datamodel.html
Number
Complex
Real
Integral
10
Rational
object
Key
instance-of
17. a class named Metaclass
SmallInteger class --> SmallInteger class
Integer class --> Integer class
Number class --> Number class
Magnitude class --> Magnitude class
Object class --> Object class
ProtoObject class --> ProtoObject class
SmallInteger class superclass --> Integer class
Integer class superclass --> Number class
Number class superclass --> Magnitude class
Magnitude class superclass --> Object class
Object class superclass --> ProtoObject class
ProtoObject class superclass --> Class
Class class --> Class class
Class class class --> Metaclass
Metaclass class --> Metaclass class
Metaclass class class --> Metaclass
20. Class class class --> Metaclass
Metaclass superclass --> ClassDescription
ClassDescription superclass --> Behavior
Behavior superclass --> Object
Class class superclass --> ClassDescription class
ClassDescription class superclass --> Behavior class
Behavior class superclass --> Object class
20
21. Object
Magnitude
Number
Object class
Magnitude class
Number class
Key
instance-of
Integer class
SmallInteger
SmallInteger class
10
Integer
ProtoObject
ProtoObject class
Class
Class class
Metaclass
Metaclass class
ClassDescription
Behavior
ClassDescription class
Behavior class
21
24. Python metaclass
• LOAD_BUILD_CLASS:
LOAD_BUILD_CLASS¶
Pushes builtins.__build_class__() onto the
stack. It is later called by CALL_FUNCTION to
construct a class [1]
• builtins.__build_class__
static PyMethodDef builtin_methods[] = {
{"__build_class__", (PyCFunction)builtin___build_class__,
METH_VARARGS | METH_KEYWORDS, build_class_doc},
{"__import__", (PyCFunction)builtin___import__,
METH_VARARGS | METH_KEYWORDS, import_doc},
{"abs", builtin_abs, METH_O, abs_doc},
[1] https://docs.python.org/3/
library/dis.html
• builtin_build_class__
• if no specific metaclass was
given and there no special
metaclass in base classes of a
class, the default metaclass is
the ‘type’
• BTW, as far as I can tell there are
some classes have non-type
metaclasses in standard Python
distribution. We know numbers
and collections
• try “grep metaclass=“ in python
source code
25. builtin_build_class__()
static PyObject *
builtin___build_class__(PyObject *self, PyObject *args, PyObject *kwds)
{
…
if (meta == NULL) {
/* if there are no bases, use type: */
if (PyTuple_GET_SIZE(bases) == 0) {
meta = (PyObject *) (&PyType_Type);
}
/* else get the type of the first base */
else {
PyObject *base0 = PyTuple_GET_ITEM(bases, 0);
meta = (PyObject *) (base0->ob_type);
}
Py_INCREF(meta);
isclass = 1; /* meta is really a class */
}
…
}
29. Bytecode
• Bytecode is not new at all
• Smalltalk is one of early bytecode users
• Smalltalk bytecode
• end of Chapter 26, http://www.mirandabanda.org/
bluebook/
bluebook_chapter26.html#TheBytecodes26
• Chap. 28, http://www.mirandabanda.org/bluebook/
bluebook_chapter28.html
30. Smalltalk bytecode categories
• pushes
• indicates the source of an object to be added to the top of the
interpreter's stack
• stores
• indicates the variable whose value should be changed
• sends
• specifies the selector of a message to be sent and how many
arguments it should have.
• returns
• a value is returned for the message that invoked that
CompiledMethod
• and jumps
• you know what these are 30
31. Smalltalk bytecodes
Range Bits FuncHon
0-15 0000iiii Push Receiver Variable #iiii
16-31 0001iiii Push Temporary LocaHon #iiii
32-63 001iiiii Push Literal Constant #iiiii
64-95 010iiiii Push Literal Variable #iiiii
96-103 01100iii Pop and Store Receiver Variable #iii
104-111 01101iii Pop and Store Temporary LocaHon #iii
112-119 01110iii Push (receiver, true, false, nil, -1, 0, 1, 2) [iii]
120-123 011110ii Return (receiver, true, false, nil) [ii] From Message
124-125 0111110i Return Stack Top From (Message, Block) [i]
126-127 0111111i unused
128 10000000 jjkkkkkk Push (Receiver Variable, Temporary LocaHon, Literal Constant, Literal Variable) [jj] #kkkkkk
129 10000001 jjkkkkkk Store (Receiver Variable, Temporary LocaHon, Illegal, Literal Variable) [jj] #kkkkkk
130 10000010 jjkkkkkk Pop and Store (Receiver Variable, Temporary LocaHon, Illegal, Literal Variable) [jj] #kkkkkk
131 10000011 jjjkkkkk Send Literal Selector #kkkkk With jjj Arguments
132 10000100 jjjjjjjj kkkkkkkk Send Literal Selector #kkkkkkkk With jjjjjjjj Arguments
133 10000101 jjjkkkkk Send Literal Selector #kkkkk To Superclass With jjj Arguments
134 10000110 jjjjjjjj kkkkkkkk Send Literal Selector #kkkkkkkk To Superclass With jjjjjjjj Arguments
135 10000111 Pop Stack Top
136 10001000 Duplicate Stack Top
137 10001001 Push AcHve Context
138-143 unused
144-151 10010iii Jump iii + 1 (i.e., 1 through 8)
152-159 10011iii Pop and Jump 0n False iii +1 (i.e., 1 through 8)
160-167 10100iii jjjjjjjj Jump(iii - 4) *256+jjjjjjjj
168-171 101010ii jjjjjjjj Pop and Jump On True ii *256+jjjjjjjj
172-175 101011ii jjjjjjjj Pop and Jump On False ii *256+jjjjjjjj
176-191 1011iiii Send ArithmeHc Message #iiii
192-207 1100iiii Send Special Message #iiii
208-223 1101iiii Send Literal Selector #iiii With No Arguments
224-239 1110iiii Send Literal Selector #iiii With 1 Argument
240-255 1111iiii Send Literal Selector #iiii With 2 Arguments
31
32. • An example method,
forCompiledMethod
"to show how CompiledMethod works"
| foo |
foo := 'test'.
^ 1 + 2
• Bytecode: in System Browser of Squeak/Pharo, we can see bytecode easily
17 <20> pushConstant: 'test'
18 <68> popIntoTemp: 0
19 <76> pushConstant: 1
20 <77> pushConstant: 2
21 <B0> send: +
22 <7C> returnTop
32
40. observations
• ST-80’s bytecode is relatively simple or say
primitive one
• Python’s bytecode has many some unique
instructions and some specialized instructions for
builtin types (for legacy or performance reasons,
maybe)
• I know ST-80’s bytecode showed its age, but I am
surprised that Python’s bytecode is low level and
old too
41. So?
• We walked through metaclass and bytecode in
ST-80 and Python? Do you agree Guido’s words I
cited previously