Skip to content

cassiobotaro/poop

Repository files navigation

POOP logo

POOP πŸ’©

POOP β€” Python Object Oriented Programming. A Python 3.14 interpreter that enforces Smalltalk-style message passing by rejecting if/for/print/isinstance and rewriting Python literals (1, "hi", True, […], {…}) into POOP types where every operation is a message to a receiver.

POOP is for educational exploration of message-passing semantics inside the Python ecosystem, not for production. Status: stable β€” breaking changes ship in major releases (1.x β†’ 2.0). POOP is not distributed via PyPI by design; clone and run it locally.

Install

git clone https://github.com/cassiobotaro/poop.git
cd poop
uv sync
uv run poop examples/basics/hello_world.py

Contributor / development setup lives in CONTRIBUTING.md.

Hello, POOP

"Hello, World!".print()

Run it:

poop hello.py            # run a file
poop                     # interactive REPL (Ctrl+D to exit)

Inside the REPL, colon-prefixed meta-commands help you explore, Smalltalk-browser style:

>>> :methods "abc"       # the messages an object understands
>>> :explain if          # why a construct is forbidden + the substitute
>>> :help                # list the meta-commands

The ten essentials

Python POOP
print(x) x.print()
if cond: … / else: cond.if_true(lambda: …) / cond.if_true_if_false(lambda: …, lambda: …)
for x in col: … col.do(lambda x: …)
while cond: … (lambda: cond).while_true(lambda: …)
len(x) x.len()
x[i] x.at(i)
x[a:b] x.slice(a, b)
not x x.not_()
x and y / x or y x.and_(lambda: y) / x.or_(lambda: y)
-x x.negated()

Full Python β†’ POOP recipe book: MIGRATION.md. Design rationale: INFECTIONS.md.

What's banned (and what to use instead)

POOP runs ~65 validators on every program. Grouped by theme:

Control flow β€” messages on a Boolean, not statements.

  • if / else / ternary β†’ cond.if_true(lambda: …) / cond.if_true_if_false(lambda: …, lambda: …)
  • for / while / match β†’ col.do(…) / (lambda: cond).while_true(…) / polymorphism
  • with / try / raise / assert β†’ With(lambda: cm()).do(…) / Try(lambda: …).except_(ExcType, lambda e: …).run() / ValueError.raise_("msg") / obj.assert_("msg")

Free functions β€” call as a method on the receiver.

  • print / len / abs / hash / round / pow / divmod / min / max / sum / sorted / reversed β†’ x.print(), x.len(), x.abs(), x.hash(), …
  • map / filter β†’ col.map(lambda x: …) / col.filter(lambda x: …)
  • ascii / bin / chr / repr / format β†’ corresponding methods on Int / Str
  • input / open β†’ "prompt".input() / Path("file").read_text()
  • iter(col) β†’ col.iter() returns an iterator; it.next() advances it

Introspection β€” call the method on the receiver, or use polymorphism.

  • isinstance(x, T) / issubclass(C, P) β†’ x.is_instance(T) / C.is_subclass(P)
  • callable(x) / id(x) / dir(x) β†’ x.callable() / x.id() / x.dir()
  • hasattr(x, n) / getattr(x, n) / setattr(x, n, v) β†’ x.has_attr(n) / x.get_attr(n) / x.set_attr(n, v)

Operator sugar β€” methods on the receiver.

  • x[i] / x[a:b] β†’ x.at(i) / x.slice(a, b)
  • not x / x and y / x or y β†’ x.not_() / x.and_(lambda: y) / x.or_(lambda: y)
  • -x / +x / ~x β†’ x.negated() / drop the + / x.bit_invert()
  • x is None / x in y β†’ x.is_none() / y.includes(x) (identity via x.is_identical(y))

Syntax shortcuts that hide behaviour.

  • comprehensions ([x for x in …], {…}, generator exprs) β†’ explicit .map / .filter / .do
  • top-level def (free functions) β†’ define as a method inside a class
  • yield / walrus := / del / global β†’ out of scope

Side-channels.

  • exec / breakpoint / exit β€” interpreter escape hatches forbidden

The full catalog with one row per validator and the substitute recipe lives in INFECTIONS.md.

Learn by example

examples/ ships 45 programs across three subfolders, grouped by what they teach.

Language basics (examples/basics/)

Idiomatic POOP (examples/idiomatic/)

Classic OO patterns (Sandi Metz / GoF) (examples/patterns/)

Creational

Structural

Behavioral

Other OO patterns (Fowler / Beck / Evans / Metz)

Type annotations

Annotations (x: int, def f(x: int) -> str:) are not evaluated at runtime in Python and do not cause errors in POOP programs, but they are misleading: POOP transforms every literal to its own types (Int, Str, …), so a variable annotated as int holds an Int at runtime. Avoid annotations in POOP code. type X = int is explicitly banned by the validator pipeline.

Where to next

About

πŸ’© POOPβ€” a Python interpreter infected by Smalltalk

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Contributors

Languages