FR: treating actor self references as initially defined
@nomeata @ggreif and I were discussing this again. This would solve the problem that you can't obtain the principal of 'this' in an actor's constructor, which is another common issue and inconvenience (e.g. https://forum.dfinity.org/t/heartbeat-improvements-timers-community-consideration/14201/134)
However, that could also be solved by treating this as defined, not undefined, to avoid the undefinedness error. Do you recall why we don't treat this as defined within the initializer? It seems like an unnecessary restriction to me, since you can't do anything with the principal anyway (message sends are verboten from the initializer.)
Originally posted by @crusso in https://github.com/dfinity/motoko/issues/2264#issuecomment-1400219196
Possible counter-example, depending on how the compiler compiles Echo.say.
actor Echo = {
let f : shared Text -> async () = Echo.say;
// Say the given phase.
public func say(phrase : Text) : async () {
};
};
This is also related to forum issue https://forum.dfinity.org/t/heartbeat-improvements-timers-community-consideration/14201/135, where a user want to access this from a time callback set up in the constructor.
Attempted workarounds like these don't work: https://m7sm4-2iaaa-aaaab-qabra-cai.ic0.app/?tag=1729196235
import { print } = "mo:base/Debug";
import { abs } = "mo:base/Int";
import { now } = "mo:base/Time";
import Principal = "mo:base/Principal";
import { setTimer; recurringTimer } = "mo:base/Timer";
actor Reminder = {
var This : Principal = Principal.fromBlob("");
private func act() : async () {
print("Happy New Year!");
};
private func ensureThis() {
if (This == Principal.fromBlob("")) {
This := Principal.fromActor(Reminder);
};
};
ignore setTimer(#seconds 5,
func () : async () {
//ensureThis(); // doesn't work
// This := Principal.fromActor(Reminder); //doesn't work
assert This != Principal.fromBlob("");
ignore recurringTimer(#seconds 5, act);
await act();
});
}