A short guide to Pony error messages

You've been through the tutorial, you've watched some videos, and now you're ready to write some Pony code. You fire up your editor, shovel coal into the compiler, and... you find yourself looking at a string of gibberish.

Don't panic! Pony's error messages try to be as helpful as possible and the ultimate goal is to improve them further. But, in the meantime, they can be a little intimidating.

This section tries to provide a short bestiary of Pony's error messages, along with a guide to understanding them.

Let's start with a simple one.

left side must be something that can be assigned to

Suppose you wrote:

actor Main
  let x: I64 = 0
  new create(env: Env) =>
    x = 12

The error message would be:

Error:
.../a.pony:6:5: can't assign to a let or embed definition more than once
    x = 12
    ^
Error:
.../a.pony:6:7: left side must be something that can be assigned to
    x = 12
      ^

What happened is that you declared x as a constant, by writing let x, and then tried to assign a new value to it, 12. To fix the error, replace let with var or reconsider what value you want x to have.

That one error resulted in two error messages. The first, pointing to the x, describes the specific problem, that x was defined with let. The second, pointing to the = describes a more general error, that whatever is on the left side of the assignment is not something that can be assigned to. You would get that same error message if you attempted to assign a value to a literal, like 3.

cannot write to a field in a box function

Suppose you create a class with a mutable field and added a method to change the field:

class Wombat
  var color: String = "brown"
  fun dye(new_color: String) =>
    color = new_color

The error message would be:

Error:
.../a.pony:4:11: cannot write to a field in a box function. If you are trying to change state in a function use fun ref
    color = new_color
          ^

To understand this error message, you have to have some background. The field color is mutable since it is declared with var, but the method dye does not have an explicit receiver reference capability. The default receiver reference capability is box, which allows dye to be called on any mutable or immutable Wombat; the box reference capability says that the method may read from but not write to the receiver. As a result, it is illegal to attempt to modify the receiver in the method.

To fix the error, you would need to give the dye method a mutable reference capability, such as ref: fun ref dye(new_color: String) => ....

receiver type is not a subtype of target type

Suppose you made a related, but slightly different error:

class Rainbow
  let colors: Array[String] = Array[String]
  fun add_stripe(color: String) =>
    colors.push(color)

In this example, rather than trying to change the value of a field, the code calls a method which attempts to modify the object referred to by the field.

The problem is very similar to that of the last section, but the error message is significantly more complicated:

Error:
../a.pony:4:16: receiver type is not a subtype of target type
    colors.push(color)
               ^
    Info:
    .../a.pony:4:5: receiver type: this->Array[String val] ref
        colors.push(color)
        ^
    .../ponyc/packages/builtin/array.pony:252:3: target type: Array[String val] ref
      fun ref push(value: A): Array[A]^ =>
      ^
    .../a.pony:2:15: Array[String val] box is not a subtype of Array[String val] ref: box is not a subtype of ref
      let colors: Array[String] = Array[String]()
                  ^

Once again, Pony is trying to be helpful. The first few lines describe the error, in general terms that only a programming language maven would like: an incompatibility between the receiver type and the target type. However, Pony provides more information: the lines immediately after "Info:" tell you what it believes the receiver type to be and the next few lines describe what it believes the target type to be. Finally, the last few lines describe in detail what the problem is.

Unfortunately, this message does not locate the error as clearly as the previous examples.

Breaking it down, the issue seems to be with the call to push, with the receiver colors. The receiver type is this->Array[String val] ref; in other words, the view that this method has of a field whose type is Array[String val] ref. In the class Rainbow, the field colors is indeed declared with the type Array[String], and the default reference capability for Strings is val while the default reference capability for Array is ref.

The "target type" in this example is the type declaration for the method push of the class Array, with its type variable A replaced by String (again, with a default reference capability of val). The reference capability for the overall array, as required by the receiver reference capability of push, is ref. It seems that the receiver type and the target type should be pretty close.

But take another look at the final lines: what Pony thinks is the actual receiver type, Array[String val] box, is significantly different from what it thinks is the actual target type, Array[String val] ref. And a type with a reference capability of box, which is immutable, is indeed not a subtype of a type with a reference capability of ref, which is mutable.

The issue must lie with the one difference between the receiver type and the target type, which is the prefix "this->". The type this->Array[String val] ref is a viewpoint adapted type, or arrow type, that describes the Array[String val] ref "as seen by the receiver". The receiver, in this case, has the receiver reference capability of the method add_stripe, which is the default box. That is why the final type is Array[String val] box.

The fundamental error in this example is the same as the last: the default receiver reference capability for a method is box, which is immutable. This method, however, is attempting to modify the receiver, by adding another color stripe. That is not legal at all.

As an aside, while trying to figure out what is happening, you may have been misled by the declaration of the colors field, let colors.... That declaration makes the colors binding constant. As a result, you cannot assign a new array to the field. On the other hand, the array itself can be mutable or immutable. In this example, it is mutable, allowing push to be called on the colors field in the add_stripe method.

A note on compiler versions

The error messages shown in this section are from ponyc 0.2.1-1063-g6ae110f [release], the current head of the master branch at the time this is written. The messages from other versions of the compiler may be different, to a greater or lesser degree.

results matching ""

    No results matching ""