Every programming language has gotchas. Those “wat” moments that make us all laugh when someone does a presentation on them. They often shoot to the top of sites like Hacker News and Reddit. It’s all in good fun, except, it isn’t. Each of those gotchas and the laughs we get from them, hide someone’s pain. This chapter covers some common Pony gotchas that new Pony programmers often stumble across with painful results. Probably the best way to approach this chapter is to imagine each section has a giant flashing “DO NOT DO THIS” sign.
What’s 1 divided by 0? How about 10 divided by 0? What is the result you get in your favorite programming language?
In math, divide by zero is undefined. There is no answer to that question as the expression 1⁄0 has no meaning. In many programming languages, the answer is a runtime exception that the user has to handle. In Pony, things are a bit different.
Divide by zero in Pony In Pony, integer division by zero results in zero.
There’s a common GC anti-pattern that many new Pony programmers accidentally stumble across. Usually, this results in a skyrocketing of memory usage in their test program and questions on Zulip as to why Pony isn’t working correctly. It is, in fact, working correctly, albeit not obviously.
Garbage Collection in the world at large Garbage collection, in most languages, can run at any time. Your program can be paused so that memory can be freed up.
The Pony scheduler is not preemptive. This means that your actor has to yield control of the scheduler thread in order for another actor to execute. The normal way to do this is for your behavior to end. If your behavior doesn’t end, you will continue to monopolize a scheduler thread and bad things will happen.
FFI and monopolizing the scheduler An easy way to monopolize a scheduler thread is to use the FFI facilities of Pony to kick off code that doesn’t return for an extended period of time.
Consider the following code:
class Foo fun fn(x: U64) => None actor Main new create(env: Env) => var x: U64 = 0 try foo()?.fn(x = 42) end env.out.print(x.string()) fun foo(): Foo ? => error What do you think it will print? Probably 0 right? Or maybe you realized this code is in the gotchas section so it must be 42. If you went with 42, you’d be right. Why?
Recursive functions in Pony can cause many problems. Every function call in a program adds a frame on the system call stack, which is bounded. If the stack grows too big it will overflow, usually crashing the program. This is an out-of-memory type of error and it cannot be prevented by the guarantees offered by Pony.
If you have a heavy recursive algorithm, you must take some precautions in your code to avoid stack overflows.