Principal from passed shared function

Is it possible to get the principal of a shared function?

for instance

public type FooFunc = shared (Foo) -> async Bar;

public shared func helloFoo(f : FooFunc) : async () {
  let p : Principal = Principal.fromFuncOrSomething(f);
}

functions don’t have their own principal, instances of the actor class have one. All functions of the actor instance - when calling other functions, appear as the same caller

Check the motoko playground “who am I” tutorial. This is the part you need from there.

import Principal "mo:base/Principal";

shared (install) actor class WhoAmI() =
  this { 
  // Return the principal identifier of the caller of this method.
  public shared (message) func whoami() : async Principal {
    return message.caller;
  };

  // Return the principal identifier of this canister.
  public func id() : async Principal {
    return await whoami();
  };

  // Return the principal identifier of this canister via the optional `this` binding.
  // This is much quicker than `id()` above, since it avoids the latency of `await whoami()`.
  public func idQuick() : async Principal {
    return Principal.fromActor(this);
  };
};

2 Likes

Appreciate your reply infu. However, I’m actually referring to a shared actor function. Another example here. Motoko does not appear to be able to extract the actor principal from a passed actor function reference.

In my case, the specific issue is I have a frontend passing me a reference shaped in JS as:

[Principal.fromText("foo-canister-whatever"), "myImportantCallbackFunction"]

Inside Motoko we type this as

public type FooFunc = shared (Foo) -> async Bar;

Ironically - in JS we don’t have to be specific about the types but have the principal and method name, and in Motoko we have the types but no way to introspect the principal or method name :joy:

@claudio - hate to ping you, but any thoughts? Hoping I’m just missing some syntax magic here.

1 Like

So you are returning a function ref to JS and wanting it to come back in as a passed param? That seems like magic. What does the original function look like that returns the function call back? Maybe I’m misunderstanding.

https://m7sm4-2iaaa-aaaab-qabra-cai.raw.ic0.app/?tag=3222031777

Oh wow…looks like it might work. But the candid UI doesn’t look like it wants to take a function back in.

Sorry was travelling and missed the ping.

Motoko does not allow you to deconstruct a shared function refence into its target actor and method name, even though that is essentially the underlying representation.

We could easily support that but I expect it’s a bad idea in general as it would be breaking the abstraction, a bit like being able to access the environment of a function closure.

@rossberg any thoughts?

Motoko already breaks the function abstraction a little as you can test whether two shared function are ‘equal’ (refer to the same actor and method) so you could abuse that to check if your (unknown) function is equal to some other known function you are aware of.

This is because == is defined on all shared types, including shared functions.

Depending on your application, that might be enough.

1 Like

I tend to agree with @claudio: such functionality would probably be a bad idea as a general language feature, since it would violate abstraction and capability principles. If some receiver needs to know the principal, can’t you pass it along separately?

2 Likes

Hmm, I can’t help but feel knowing “who” a shared function belongs to is incredibly important. The workaround of passing the principal along with the shared func will work, but my worry is this will make building access scopes funky - the data is there, but now I need to stash a principal Id where-ever I store the ref… Moreover, surfacing actionable errors when shared function are acting up becomes a lot more challenging.

FWIW if we ever expose Candid serialisation functions as generic toBlob/from Blob primitives then users will be able to break the abstraction anyway, by inspecting the serialized bytes of a shared function.

So perhaps the horse will bolt anyway…

1 Like