"Cannot infer type of forward field reference" error when using a static module function in a class constructor

Let’s say I have a module with a class, and a collection of static functions.

I’m currently unable to use one of these static functions in the class constructor if this static function lies in the same file as my module.

module {
  public func somethingStaticAndUseful(counter: Nat): Nat {
    counter + 1;
  };

  public class Clazz(counter: Nat) {
    //  shows error: "cannot infer type of forward field reference somethingStaticAndUseful"
    var counter = somethingStaticAndUseful(counter);
  }
}

However, if I put the somethingStaticAndUseful() function in another file and import it, the code compiles without any errors.

Ideally, if I’m publishing a module, I’d like to include both the class and the static function in the same file and not have to copy/paste the code from the static function into the logic of the constructor.

For example, I don’t want to have to do this:

module {
  public func somethingStaticAndUseful(counter: Nat): Nat {
    counter + 1;
  };

  public class Clazz(counter: Nat) {
    //  if I copy the logic from the static function in here, it compiles
    var counter = counter + 1;
    //  this is a simple example, but it's frustrating if there's more 
    //  complicated logic in the static function that may call other 
    //  "helper" functions located in the same module
  }
}
1 Like

The error message is rather misleading, but it looks like you just forgot to give somethingStatic a return type. Try:

public func somethingStaticAndUseful(counter: Nat) : Nat {
    counter + 1;
};

@rossberg Thanks for the suggestion! Unfortunately this doesn’t fix the error described.

I just updated the code example and the Motoko playground link in the original post to demonstrate that this error is still occurring after adding the Nat return type.

1 Like

There are two problems: (1) the inner counter shadows the outer (such that the argument refers to the wrong one), and (2) in classes, the types of var declarations cannot always be inferred early enough. This works for me:

  public class Clazz(c : Nat) {
    var counter : Nat = somethingStaticAndUseful(c);
  }

It’s generally good practice to put types on var declarations (I remember we have even discussed making them mandatory, at least in classes).

2 Likes

Thanks for the help, the example above was somewhat contrived, but it ended up being that case that putting a type on the instance variable with the class fixes the issue.

// What I was previously doing
public class Clazz(arg : Nat) {
  let instanceVariable = staticFunction(arg)` // <- forward reference error
};

// The Solution
public class Clazz(arg : Nat) {
  let instanceVariable: Nat = staticFunction(arg) // Note the type added (`: Nat`)
}

This seems somewhat arbitrary that the instance variable would need a type (can just look at the return type of staticFunction(). Also that the error message is a bit misleading.

1 Like

The problem is that everything can be mutually recursive, i.e., the type annotations on functions may themselves refer to class types. To unravel possible recursion, type checking proceeds in stages, the first one being collecting all named type definitions in a scope. A class is a form of type definition, but its meaning in turn has to be derived from its fields – before it has looked at functions, which is where the example failed. The type system could of course be more clever (e.g. require a dependency analysis or a fixpoint iteration), but this aspect is already pretty complicated and costly as is.

I agree the error message could be improved, though.

1 Like